Reputation: 71
import smtplib
smtpObj = smtplib.SMTP('smtp.office365.com', 587)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login('[email protected]', ' abcde')
smtpObj.sendmail('[email protected]', '[email protected]', 'Subject: So long.\nDear Alice, so long and thanks for all the fish. Sincerely, Bob')
{}
smtpObj.close()
The error I am getting
SMTPAuthenticationError: (535, b'5.7.3 Authentication unsuccessful [BM1PR01CA0150.INDPRD01.PROD.OUTLOOK.COM]').
Upvotes: 7
Views: 27406
Reputation: 11
There is a way to send the email without compromising your security:
Given that Outlook (and Microsoft 365) generally encourages secure practices, the recommended way to send emails without reducing security is by using the Microsoft Graph API with OAuth 2.0 for authentication.
There is a way to send the email without compromising your security. It will require using secure authentication methods. Given that Outlook (and Microsoft 365) generally encourages secure practices, the recommended way to send emails without reducing security is by using the Microsoft Graph API with OAuth 2.0 for authentication.
Set Up an Azure App Registration:
http://localhost
).Configure Permissions for the App:
Mail.Send
permission, among others, depending on your requirements.Set Up Authentication with OAuth 2.0:
Use Microsoft Authentication Library (MSAL) in Python:
msal
(Microsoft Authentication Library) in your Python environment:
pip install msal
Write Python Code to Send an Email:
msal
library to get an access token, then use this token to send an email via Microsoft Graph. Here's a simplified example of how to do this:
import msal
import requests
# Set up your application details
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET_VALUE"
tenant_id = "YOUR_TENANT_ID"
authority = f"https://login.microsoftonline.com/{tenant_id}"
scope = ["https://graph.microsoft.com/.default"]
# Get an access token
app = msal.ConfidentialClientApplication(authority=authority, client_id=client_id, client_credential=client_secret)
result = app.aquire_token_for_client(scope)
access_token = result['access_token']
# Define email data
email = {
"message": {
"subject": "Email Subject!",
"body": {
"contentType": "Text",
"content": " EmailContent"
},
"toRecipients": [
{
"emailAddress": {
"address": "RECIPIENT_EMAIL"
}
}
]
}
}
# Send the email
sender_userid = "EMAIL_USER_ID"
endpoint = f'https://graph.microsoft.com/v1.0/users/{sender_userid}/sendMail'
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
response = requests.post(endpoint, json=email, headers=headers)
if response.status_code == 202:
print("Email sent successfully")
else:
print(f"Failed to send email: {response.status_code}")
This did it for me!
Upvotes: 0
Reputation: 25
Thanks @wombatonfire - very helpful - I have a small addition to your answer.
I tried for a few hours to setup up multiple email addresses to send mail from a Python script; all of the accounts I was working with showed Authenticated SMTP to be enabled on the Active User page, but I was still getting authentication errors.
Not until I deselected and re-selected the "Authenticated SMTP" checkbox for each account did the script work.
Thanks
Upvotes: 1
Reputation: 1
@wombatonfire gave a terrific answer, but if for any reason those steps aren't possible (as was my situation), the following solved the OP problem for me.
I'm on a Mac. Can't get to admin center. Had to use powershell. Also, powershell on my Mac had to connect to MSFT exchange server before I could change the setting for my mailbox. The following makes email work as designed.
There is a critical hoop to jump through to make this all work. To connect your Mac to MSFT Exchange server, your Mac must use TLS1.2 from/via/through OpenSSL1.0. OpenSSL1.1 is a no go.
Get a terminal window on your Mac:
Click LaunchPad, type "term", click Terminal
In the terminal window, check what version(s) of OpenSSL are on your Mac:
>ls -al /usr/local/Cellar/openssl*
See which what version is active:
>openssl version -a
OpenSSL 1.1.* is bad. OpenSSL 1.0.* is good.
NORMALLY, you can use brew to switch versions of a package is active with:
>brew switch openssl 1.0.2s
>brew link --overwrite openssl
But I got this error: Warning: Refusing to link macOS provided/shadowed software: openssl. So I had to get tricky.
Change PATH environment variable (just in this terminal session, not permanently).
>PATH=/usr/local/Cellar/openssl/1.0.2s/bin:$PATH
Now the check, shows good version:
>openssl version -a
Next, I followed steps to install powershell documented here: https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-macos?view=powershell-7
Now, open powershell as admin.
>sudo su - root
<your mac password>
root>pwsh
At the powershell prompt, double check your powershell version. Version 7 is needed.
>$host.version
I have: 7.0.3 Revision -1
Check what modules are installed in powershell:
>Get-Module -ListAvailable
If "PowerShellGet" is not listed, install it:
>Install-Module -Name PowerShellGet -Force
This next step is critical to success on the Mac. Only the latest "preview version 2.0.4" of "ExchangeOnlineManagement" package is going to work on Mac.
I don't know if this is needed, but I uninstalled the released version of "ExchangeOnlineManagement" package with:
>Uninstall-Module -Name ExchangeOnlineManagement -RequiredVersion 2.0.3
If preview version not present, install it:
>Install-Module -Name ExchangeOnlineManagement -AllowPrerelease -Force
One last detail to take care of. Tell powershell what version of TLS you want "ExchangeOnlineManagement" package to use:
>[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Finally, it's time to connect to the mothership: (Again, this is trickier on a Mac than in Windows, probably).
>Connect-ExchangeOnline -UserPrincipalName youremail@yourdomain
The above command will try to open a browser to a special authentication page. At least on my Mac, it couldn't. So:
COPY the giant link that gets displayed in the powershell window
PASTE the giant link into a web browser (I used Safari).
After you enter your Exchange credentials on that browser page, your powershell will show a progress bar for a short time, then magically be connected to MSFT Exchange server!
And the last step to set the SMTP setting on the mailbox you want to use:
Set-CASMailbox -Identity youremail@yourdomain -SmtpClientAuthenticationDisabled $false
Lastly, apparently it's important to always explicitly disconnect (before closing the terminal window):
>Disconnect-ExchangeOnline
That's the ballgame. You are changing the "disabled" setting to false for each/any/all mailboxes you want to send email from.
Now the fully documented, oft repeated python code seen in the OP will use SMTP and TLS to send email via MSFT Exchange (until something else breaks it all again :-O ).
Enjoy!
Upvotes: 0
Reputation: 5410
Most likely, the authenticated SMTP (SMTP AUTH protocol) is disabled in your Exchange Online organization.
SMTP AUTH can be enabled/disabled on the organization level, or per-mailbox. Because SMTP AUTH only uses basic authentication, Microsoft recommends to disable it on the organization level and enable it only for individual accounts that still require it.
If security defaults are enabled in the organization, then SMTP AUTH is disabled.
SMTP AUTH can be enabled in Microsoft 365 admin center or using Exchange Online Powershell.
To make it simple, to enable SMTP AUTH for a single account:
After that you should be able to authenticate using the respective account.
Important: You need admin rights in your Office 365 organization to do that. Otherwise, ask your O365 org admin for help.
Further details: https://learn.microsoft.com/exchange/clients-and-mobile-in-exchange-online/authenticated-client-smtp-submission
Upvotes: 10