How to send SMTP email for office365 with python using tls/ssl
Solution 1
Well, you are almost there. The following code will do the trick:
import smtplib
mailserver = smtplib.SMTP('smtp.office365.com',587)
mailserver.ehlo()
mailserver.starttls()
mailserver.login('[email protected]', 'password')
#Adding a newline before the body text fixes the missing message body
mailserver.sendmail('[email protected]','[email protected]','\npython email')
mailserver.quit()
Use the following links for more information:
http://www.aventistech.com/2016/03/07/python-send-email-via-office-365-tls/
https://docs.python.org/3/library/smtplib.html
https://gist.github.com/jasonjoh/3ec367594c3fa662ee983a617bdc7deb
Solution 2
I found a library that it's working for me:
https://github.com/O365/python-o365
https://pypi.python.org/pypi/O365
Install it using PIP and then:
from O365 import Message
o365_auth = ('[email protected]','YourPassword')
m = Message(auth=o365_auth)
m.setRecipients('[email protected]')
m.setSubject('I made an email script.')
m.setBody('Talk to the computer, cause the human does not want to hear it any more.')
m.sendMessage()
Solution 3
The code has slightly changed. The above code won't work. Please use the below code. Reference
from O365 import Account
credentials = ('client_id', 'client_secret')
account = Account(credentials)
m = account.new_message()
m.to.add('[email protected]')
m.subject = 'Testing!'
m.body = "George Best quote: I've stopped drinking, but only while I'm asleep."
m.send()
Solution 4
Most likely, the problem is not in your code, but in the Exchange Online configuration.
I bet 535 5.7.3 Authentication unsuccessful
is thrown because authenticated SMTP (SMTP AUTH protocol) is disabled in your Exchange Online organization.
Here you can find my answer explaining how you can enable SMTP AUTH for the user you are sending emails from. You have to be an Office 365 org admin to do that, or you can ask your administrator for help.
After that mailserver.starttls()
should work. Notice that you don't need to specify a certificate in that call.
Solution 5
For me the answer provided by @Prometheus was giving "RuntimeError: No auth token found . Authentication Flow needed" as mentioned by a comment. It maybe because of my company email with 2fa enabled. So I had to follow steps provided in https://github.com/janscas/pyo365#authentication and https://pypi.org/project/O365/#authentication
To work with oauth you first need to register your application at Microsoft Application Registration Portal.
- Login at Microsoft Application Registration Portal
- Create an app, note your app id (client_id)
- Generate a new password (client_secret) under "Application Secrets" section Under the "Platform" section, add a new Web platform and set https://login.microsoftonline.com/common/oauth2/nativeclient" as the redirect URL
- Goto API permissions > Add permission > Microsoft Graph > Delegated permissions, add the permissions below:
- Run below python script to obtain access token which will be stored in file called o365_token.txt in current directory
from O365 import Account
scopes = ["IMAP.AccessAsUser.All", "POP.AccessAsUser.All", "SMTP.Send", "Mail.Send", "offline_access"]
account = Account(credentials=('client_id_of_azureapp', 'client_secret_of_azureapp'))
result = account.authenticate(scopes=scopes) # request a token for this scopes
- Use below script to send email by providing the authtoken file generated in previous step.
from O365 import Account
from O365.utils.token import FileSystemTokenBackend
tk = FileSystemTokenBackend(token_path=".", token_filename="o365_token.txt")
credentials = ('client_id') # client secret not required
account = Account(credentials, auth_flow_type = 'public',token_backend=tk)
m = account.new_message()
m.to.add('[email protected]')
m.subject = 'Testing!'
m.body = "George Best quote: I've stopped drinking, but only while I'm asleep."
m.send()
Note: If you have admin consent or you are administrator or azure account you can skip the step 4,5,6 and use below code directly.
from O365 import Account
from O365.utils.token import FileSystemTokenBackend
tk = FileSystemTokenBackend(token_path=".", token_filename="o365_token.txt")
credentials = ('client_id', 'client_secret') # from step 2,3
account = Account(credentials, auth_flow_type = 'credentials', tenant_id="your_app_tenant_id") # tenant_id (required) available just below client_id in azure
if account.authenticate():
print('Authenticated!')
mailbox = account.mailbox("[email protected]") # Your email (required) from which you want to send email (your app should have permission to this email)
m = mailbox.new_message()
m.to.add('[email protected]')
m.subject = 'Testing!'
m.body = "George Best quote: I've stopped drinking, but only while I'm asleep."
m.send()
Related videos on Youtube
TKerr
Updated on February 17, 2022Comments
-
TKerr about 2 years
I am trying to send an email from my office365 corporate account using python. I am new to python. This code previously worked when using my hotmail account, however now that I have a need to send confidential information, I must use my corporate email.
I have tried a couple things.
- Verified that my username and password is correct.
- Used both python2 and python3. Both give the same error:
535 5.7.3 Authentication unsuccessful
- I previously was using mailserver.starttls() when I got the
above error, then after some research, I tried to pass a
certificate.mailserver.starttls(certfile='office365.cer')
I am unclear on the certificate part, but my steps include, looking online to find out how to export a certificate. Using chrome browser, microsoftonline.com has a chain certificate. I can export the root and the level just below the root but not the last level. I dont know how to pass both of these files, so I have simply passed the root certificate. At this point I get the error:
ssl.SSLError: [SSL] PEM lib (_ssl.c:3309)
i got stuck at this point. Any help is appreciated. Code used below
import smtplib mailserver = smtplib.SMTP('smtp.office365.com',587) mailserver.ehlo() mailserver.starttls(certfile='office365.cer') mailserver.ehlo() mailserver.login('[email protected]', 'password') mailserver.sendmail('[email protected]','[email protected]','python email') mailserver.quit()
-
BigGerman over 5 yearsI just want to point out for anyone seeing this in the future; while this library works, it does not use SMTP. It uses the Microsoft Outlook/Graph API in order to access your Office 365 account and send emails. See Gal's answer below if you want to use SMTP.
-
Jan Wilmans over 5 yearsNOTICE: the use of smtplib.SMTP() instead of smtplib.SMTP_SSL() ! With smtplib.SMTP_SSL() you will still get the "[SSL: WRONG_VERSION_NUMBER]" error. replacing it with smtplib.SMTP() worked for me.
-
stefan.at.wpf about 5 yearshow secure is this code? What happens if the server refuses to use TLS? will the connection go unencrypted or be aborted?
-
Slowat_Kela almost 5 yearscould I ask a question about this? Gal Silberman's answer 'works' for me, as in the recipient gets an email from me, however, the email is empty (they don't even see the 'python email' string). Would anyone know why this would be? I don't get an errors, so hard to diagnose.
-
Gal Silberman almost 5 years@Kela, you should ask a new question in a different thread with everything that you did.
-
Umar.H almost 5 years@BigGerman for us mere mortals, can you explain the difference, what will the use of this code do differently from the above?
-
BigGerman almost 5 years@Datanovice SMTP is a protocol for sending emails, with smtplib you are sending the email directly to the Office365 mail server using the SMTP protocol. With nacho-parra's answer you are using a Python module (O365) which uses sends an HTTP request to the Microsoft Graph API which then sends the email. It's basically same result (email gets sent) but different methods. The original question was asking about sending using SMTP so gal-silberman's answer is the one that actually shows how to accomplish that.
-
Umar.H almost 5 years@BigGerman you are the man, very succinct and to the point edition, cheers. I wonder which is more expensive resource wise, or if the api has a limit on emails.
-
BigGerman almost 5 years@Datanovice SMTP is definitely simpler for sending a basic email, the graph API allows you to do a lot more besides just send email though. As far as rate limits for the API, they are pretty generous but they do have some throttling. Only time I ran into throttling was when retrieving like 10,000+ messages from an email inbox. SMTP servers can also have their own limits set by the provider though, see here.
-
Umar.H almost 5 years@BigGerman that is very relevant for my use case, I'm looking at a way to automate compliance via a few python scripts and email this out to my store managers, around 450 in total. I think I'll be fine with the limits.
-
Shashi Shankar Singh over 4 yearsI get the below error while using this.. "RuntimeError: No auth token found. Authentication Flow needed"
-
tomatoeshift almost 4 yearsthe row
mailserver.ehlo()
is not necessary. Fromstarttls()
documentation: "If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first." -
zhark almost 4 yearsPerhaps this is obvious, but if your corporate account requires multi-factor authentication, username and pw are inadequate to authenticate.
-
Daniel W. over 3 years@ShashiShankarSingh did you setup the client token in Azure?
-
Deepak V over 2 yearsHi, I have a strange issue, the above sequence of code works perfectly when I am executing it on the Python interpreter terminal. However, if I put the code into a .PY file and run it on VS Code or the Mac terminal, it hangs! :( Any pointers, please?
-
Gal Silberman over 2 years@DeepakV It is probably something else in your code. This is just a fix for the original question. You should post a new thread with your debuging results.
-
Deepak V over 2 yearsNo @GalSilberman I promise, it is the same code copy-pasted into a .py file :( That is why I am splitting my hair. When I run it as a python program, the code is stuck at the following place:
mailserver = smtplib.SMTP('smtp.office365.com',587)
the terminal continues to put out a blank line and the execution waits... -
Deepak V over 2 yearsSince this is the first line, do you have any pointers as to if I can enable some option in Python like
python3 -debug send_email.py
to print what is happening when I callmailserver = smtplib.SMTP('smtp.office365.com',587)
? -
Gal Silberman over 2 yearsIt has been a few years since the original answer. Things might have changed in the package. Try to follow the examples from docs.python.org/3/library/smtplib.html on how to use the package.
-
Deepak V over 2 yearsIt got interesting, I found that a Python program can be debugged using
python3 -m pdb <file.py>
I did that and did evaluation step by step, then it is working if I step inside the functionsmtplib.SMTP('smtp.office365.com',587)
, however, if I use the command 'n' to step over the function, it still has the same behavior - it gets stuck. -
A Yashwanth about 2 years@Shashi Shankar Singh See my answer stackoverflow.com/a/71148071/9160306 I was able to resolve this issue.