Repository navigation
Authenticate M365 SMTP via OAuth2 certificate instead of password - #45
Merged
Merged
Conversation
Microsoft 365 has disabled Basic Authentication (username/password) for SMTP AUTH, so email_sender.py could no longer log in with a mailbox password. Switch to app-only (client-credentials) OAuth2 using a certificate, and send via the SMTP XOAUTH2 mechanism. - email_sender.py: acquire an app-only access token from Entra ID via MSAL using a certificate credential (private key + SHA-1 thumbprint computed from the PEM), then authenticate with AUTH XOAUTH2 instead of SMTP.login(). Load .env from the project root so cron runs resolve it. - dialogueBox.py: replace the "Email Password" field with Tenant ID, Client ID, and Certificate Path (with a Browse button); persist as AZURE_TENANT_ID / AZURE_CLIENT_ID / AZURE_CERT_PATH. - requirements.txt / initial_setup.sh: add msal and cryptography (the cron venv installs them too). - .env.example: replace EMAIL_PASSWORD with the AZURE_* keys. - README.md: add a "Microsoft 365 email setup" section covering the app registration, SMTP.SendAsApp admin consent, self-signed certificate creation/upload, and Exchange Online mailbox scoping.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Microsoft 365 has disabled Basic Authentication (username/password) for SMTP AUTH. The scheduled report in
src/email_sender.pyusedsmtplib.SMTP.login(sender, password), which M365 now rejects — the nightly email fails to send.What
Switch to app-only (client-credentials) OAuth2 using a certificate, and send via the SMTP
XOAUTH2mechanism. No mailbox password is used or stored.src/email_sender.py— acquire an app-only access token from Entra ID via MSAL using a certificate credential (private key + SHA-1 thumbprint computed from the PEM), then authenticate withAUTH XOAUTH2instead ofSMTP.login(). Thesmtp.office365.com:587STARTTLS connection and domain→server mapping are unchanged. Also loads.envfrom the project root so cron runs resolve it regardless of working directory.src/dialogueBox.py— the "Email Password" field is replaced by Tenant ID, Client ID, and Certificate Path (with a Browse file-picker), persisted asAZURE_TENANT_ID/AZURE_CLIENT_ID/AZURE_CERT_PATH.requirements.txt/scripts/initial_setup.sh— addmsalandcryptography; the cron.venvinstalls them too..env.example—EMAIL_PASSWORD→ theAZURE_*keys.README.md— new "Microsoft 365 email setup" section: app registration,SMTP.SendAsAppapplication permission + admin consent, self-signed certificate creation/upload, and Exchange Online mailbox scoping (New-ServicePrincipal/Add-MailboxPermission/Set-CASMailbox).Admin prerequisites (one-time, per README)
Requires an Entra ID admin to register an app, grant
SMTP.SendAsApp(admin consent), upload the public certificate, and scope the service principal to the sender mailbox.Verification
openssl x509 -fingerprint -sha1and MSAL's own internal computation (cert.fingerprint(hashes.SHA1()).hex())..venv/bin/python src/email_sender.py—set_debuglevel(1)prints the SMTP conversation, including the235auth-success line.