How to send SMTP email for office365 with python using tls/ssl

70,253

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.

  1. Login at Microsoft Application Registration Portal
  2. Create an app, note your app id (client_id)
  3. 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
  4. Goto API permissions > Add permission > Microsoft Graph > Delegated permissions, add the permissions below:
    • IMAP.AccessAsUser.All

    • Mail.Send

    • POP.AccessAsUser.All

    • User.Read

    • SMTP.Send

    • offline_access # If you want refresh token to be avaialble in o365_token.txt. Otherwise you need to get access token every 1hr. enter image description here

  5. 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
  1. 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()
Share:
70,253

Related videos on Youtube

TKerr
Author by

TKerr

Updated on February 17, 2022

Comments

  • TKerr
    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
    BigGerman over 5 years
    I 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
    Jan Wilmans over 5 years
    NOTICE: 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
    stefan.at.wpf about 5 years
    how secure is this code? What happens if the server refuses to use TLS? will the connection go unencrypted or be aborted?
  • Slowat_Kela
    Slowat_Kela almost 5 years
    could 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
    Gal Silberman almost 5 years
    @Kela, you should ask a new question in a different thread with everything that you did.
  • Umar.H
    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
    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
    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
    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
    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
    Shashi Shankar Singh over 4 years
    I get the below error while using this.. "RuntimeError: No auth token found. Authentication Flow needed"
  • tomatoeshift
    tomatoeshift almost 4 years
    the row mailserver.ehlo() is not necessary. From starttls() documentation: "If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first."
  • zhark
    zhark almost 4 years
    Perhaps this is obvious, but if your corporate account requires multi-factor authentication, username and pw are inadequate to authenticate.
  • Daniel W.
    Daniel W. over 3 years
    @ShashiShankarSingh did you setup the client token in Azure?
  • Deepak V
    Deepak V over 2 years
    Hi, 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
    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
    Deepak V over 2 years
    No @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
    Deepak V over 2 years
    Since 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 call mailserver = smtplib.SMTP('smtp.office365.com',587) ?
  • Gal Silberman
    Gal Silberman over 2 years
    It 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
    Deepak V over 2 years
    It 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 function smtplib.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
    A Yashwanth about 2 years
    @Shashi Shankar Singh See my answer stackoverflow.com/a/71148071/9160306 I was able to resolve this issue.