From ba4ff2e74b43bb13649bfe9d1d287070c4ac898c Mon Sep 17 00:00:00 2001 From: "vladimir.buzalka" Date: Fri, 12 Dec 2025 14:29:24 +0100 Subject: [PATCH] z230 --- SendEmailsSolution/10 test1.py | 7 ++ SendEmailsSolution/EmailMessagingGraph.py | 91 +++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 SendEmailsSolution/10 test1.py create mode 100644 SendEmailsSolution/EmailMessagingGraph.py diff --git a/SendEmailsSolution/10 test1.py b/SendEmailsSolution/10 test1.py new file mode 100644 index 0000000..38061b9 --- /dev/null +++ b/SendEmailsSolution/10 test1.py @@ -0,0 +1,7 @@ +from EmailMessagingGraph import send_mail + +send_mail( + to="vladimir.buzalka@buzalka.cz", + subject="Hotovo", + body="Report doběhl OK.", +) diff --git a/SendEmailsSolution/EmailMessagingGraph.py b/SendEmailsSolution/EmailMessagingGraph.py new file mode 100644 index 0000000..6e5ea25 --- /dev/null +++ b/SendEmailsSolution/EmailMessagingGraph.py @@ -0,0 +1,91 @@ +""" +EmailMessagingGraph.py +---------------------- +Private Microsoft Graph mail sender +Application permissions, shared mailbox +""" + +import msal +import requests +from functools import lru_cache +from typing import Union, List + + +# ========================= +# PRIVATE CONFIG (ONLY YOU) +# ========================= +TENANT_ID = "7d269944-37a4-43a1-8140-c7517dc426e9" +CLIENT_ID = "4b222bfd-78c9-4239-a53f-43006b3ed07f" +CLIENT_SECRET = "Txg8Q~MjhocuopxsJyJBhPmDfMxZ2r5WpTFj1dfk" +SENDER = "reports@buzalka.cz" + + +AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}" +SCOPE = ["https://graph.microsoft.com/.default"] + + +@lru_cache(maxsize=1) +def _get_token() -> str: + app = msal.ConfidentialClientApplication( + CLIENT_ID, + authority=AUTHORITY, + client_credential=CLIENT_SECRET, + ) + + token = app.acquire_token_for_client(scopes=SCOPE) + + if "access_token" not in token: + raise RuntimeError(f"Graph auth failed: {token}") + + return token["access_token"] + + +def send_mail( + to: Union[str, List[str]], + subject: str, + body: str, + *, + html: bool = False, +): + """ + Send email via Microsoft Graph. + + :param to: email or list of emails + :param subject: subject + :param body: email body + :param html: True = HTML, False = plain text + """ + + if isinstance(to, str): + to = [to] + + payload = { + "message": { + "subject": subject, + "body": { + "contentType": "HTML" if html else "Text", + "content": body, + }, + "toRecipients": [ + {"emailAddress": {"address": addr}} for addr in to + ], + }, + "saveToSentItems": "true", + } + + headers = { + "Authorization": f"Bearer {_get_token()}", + "Content-Type": "application/json", + } + + r = requests.post( + f"https://graph.microsoft.com/v1.0/users/{SENDER}/sendMail", + headers=headers, + json=payload, + timeout=30, + ) + + if r.status_code != 202: + raise RuntimeError( + f"sendMail failed [{r.status_code}]: {r.text}" + )