Bonjour !
J'ai récemment essayé d'accéder à une boîte mail Office 365 de mon client via IMAP à l'aide d'un script Python, mais cela ne fonctionne pas.
Je souhaite que le script s'exécute comme une tâche planifiée sur mon serveur, sans avoir à remplir de fenêtres de connexion contextuelles. Le script se connecte à la boîte mail, recherche une adresse mail spécifique correspondant à certains arguments et renvoie 1 ou 0 selon que l'adresse est trouvée ou non.
Pour l'instant, j'obtiens l'erreur suivante :
58:43.42 > b'MHPG1 AUTHENTICATE XOAUTH2'
58:43.43 < b'+ '
58:43.43 write literal size 3376
58:43.45 < b'MHPG1 NO AUTHENTICATE failed.'
58:43.45 NO response: b'AUTHENTICATE failed.'Erreur IMAP OAuth2: AUTHENTICATE failed.
Toute aide serait grandement appréciée ! Merci d'avance !
Notes :
Ce que j'ai fait :
- Création d'application :
a. J'ai créé une application métier sur Entra et lui ai accordé l'autorisation suivante (autorisation acceptée par un administrateur locataire) :

b. J'ai également créé la politique d'accès aux applications suivante :
New-ApplicationAccessPolicy -AppId {applicationID} -PolicyScopeGroupId {the_only_mailbox_i_want_to_access} -AccessRight RestrictAccess -Description "Restrict access to {the_only_mailbox_i_want_to_access} only"
Et j'ai testé :
Test-ApplicationAccessPolicy -AppId {applicationID} -Identity {the_only_mailbox_i_want_to_access}
AppId : {applicationID}
Mailbox : technique
MailboxId : {some_mailbox_id}
MailboxSid : {some_other_id}
AccessCheckResult : Accordé
- Script code
main.py
#!/usr/bin/env python3
import argparseimport osimport sys
from dotenv import load_dotenv
from mail_utils.imap_connection import connect_to_imap
from mail_utils.msal_auth import get_msal_tokenfrom mail_utils.imap_oauth2 import connect_to_imap_oauth2from mail_utils.email_search import search_emailsload_dotenv()# Variables généralesEMAIL_USERNAME = os.getenv("EMAIL_USERNAME", "")EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD", "")# Variables O365 MSALTENANT_ID = os.getenv("TENANT_ID", "")CLIENT_ID = os.getenv("CLIENT_ID", "")CLIENT_SECRET = os.getenv("CLIENT_SECRET", "")def main():parser = argparse.ArgumentParser(description="Recherche mail IMAP Gmail ou O365 avec OAuth2")parser.add_argument('-m', '--minutes', type=int, required=True)parser.add_argument('-f', '--folder', type=str, default="INBOX")parser.add_argument('-s', '--sender', type=str, required=True)parser.add_argument('--subject', type=str, default="")parser.add_argument('--body', type=str, default="")parser.add_argument('--provider', choices=['gmail', 'o365'], default='gmail', help="Choix du provider mail")args = parser.parse_args()if args.provider == 'gmail':# Connexion classique avec login + mdpimap = connect_to_imap("imap.gmail.com", EMAIL_USERNAME, EMAIL_PASSWORD)else:# O365 avec OAuth2scope = ["https://outlook.office365.com/.default"]access_token = get_msal_token(TENANT_ID, CLIENT_ID, CLIENT_SECRET, scope)imap = connect_to_imap_oauth2("outlook.office365.com", EMAIL_USERNAME, access_token)try:found = search_emails(imap,folder=args.folder,sender=args.sender,subject_filter=args.subject,body_filter=args.body,minutes=args.minutes)finally:imap.logout()if found:print("1")sys.exit(0)else:print("0")sys.exit(1)if name == "main":main()
msal_auth.py
import msal
import sysdef get_msal_token(tenant_id: str, client_id: str, client_secret: str, scope: list):"""Obtient un token OAuth2 via client credentials flow MSAL."""authority = f"https://login.microsoftonline.com/{tenant_id}"app = msal.ConfidentialClientApplication(client_id=client_id,client_credential=client_secret,authority=authority,)result = app.acquire_token_for_client(scopes=scope)if "access_token" in result:return result["access_token"]else:print("Erreur d'acquisition du token MSAL:")print(result.get("error"))print(result.get("error_description"))print(result.get("correlation_id"))sys.exit(1)
imap_oauth2.py
import base64
import imaplibimport sysdef generate_oauth2_string(username, access_token):"""Génère la chaîne d’authentification XOAUTH2 encodée en base64."""auth_string = f'user={username}\x01auth=Bearer {access_token}\x01\x01'return base64.b64encode(auth_string.encode()).decode()def connect_to_imap_oauth2(server: str, username: str, access_token: str):"""Connexion IMAP via XOAUTH2 (OAuth2) pour Office365."""imap = imaplib.IMAP4_SSL(server)imap.debug = 4auth_string = generate_oauth2_string(username, access_token)try:resp_code, resp_data = imap.authenticate('XOAUTH2', lambda x: auth_string.encode())if resp_code != 'OK':print("Erreur d'authentification IMAP OAuth2:", resp_data)sys.exit(1)print("Connexion IMAP OAuth2 réussie")return imapexcept imaplib.IMAP4.error as e:print(f"Erreur IMAP OAuth2: {e}")sys.exit(1)
-----------------------
Note de la modérationNous sommes sur un forum francophone, on y parle couramment le français. Merci d'écrire en français, ça simplifie la compréhension pour tous (et aussi un peu le travail des modérateurs - cette réponse a été traduite "manuellement"). 😉