92 lines
2.1 KiB
Python
92 lines
2.1 KiB
Python
"""
|
|
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}"
|
|
)
|