Add "prefer SMTP" toggle to skip Microsoft Graph for email
When the M365 connector is connected the app always tries Graph first, and a Graph 202 ends the send — so report mail to recipients Exchange silently drops (Google-hosted subdomains of the O365 domain) never reaches them, even with working SMTP configured. New prefer_smtp flag gates all three Graph branches (smtp_test, send_report, _maybe_send_auto_email) so they go straight to SMTP. UI toggle #st-smtpPreferSmtp in Settings → E-mailrapport, saved/loaded by scheduler.js, with da/de/en strings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
526e2b0b78
commit
874c3ccec1
8 files changed
+20
-5
No files matched your search
@@ -70,6 +70,7 @@ Exception hierarchy (all inherit `M365Error(Exception)`):
|
||||
- **Gmail vs Google Workspace** — auth error handlers check if SMTP username ends in `@gmail.com`/`@googlemail.com`; custom domains are treated as Google Workspace and error message points to the Workspace admin console.
|
||||
- **Canonical SMTP config keys are `username` and `use_tls`** — all backend readers (`smtp_test`, `_send_report_email`, `_send_email_graph`) use these. The Settings → E-mailrapport tab (`scheduler.js`) historically saved `user`/`starttls`, which left `username` empty so `server.login()` was skipped and the server rejected the send. Frontend now sends the canonical keys, and `_load_smtp_config()` normalises legacy `user`→`username` / `starttls`→`use_tls` for already-saved configs. The send-report modal (`scan.js`) already used the canonical keys. Keep both UIs and the backend on `username`/`use_tls`.
|
||||
- **Graph 202 ≠ delivered** — `_send_email_graph` returns on Graph's HTTP 202 (queued), and `smtp_test`/`send_report` treat that as success and never fall back to SMTP. A recipient on a domain Exchange Online considers an accepted/internal domain (e.g. a Google-hosted subdomain of the O365 domain) is silently dropped after the 202. There is no in-app fix for that routing; reaching such recipients requires SMTP (e.g. Google Workspace `smtp.gmail.com`/`smtp-relay.gmail.com`) or fixing Exchange Accepted Domains.
|
||||
- **`prefer_smtp` config flag** — when truthy, `smtp_test`, `send_report`, and `_maybe_send_auto_email` (routes/scan.py) skip the Graph path entirely and send via SMTP. This is the in-app escape hatch for the Graph-202 routing trap above. The gate is `... and not smtp_cfg.get("prefer_smtp")` on each Graph branch — keep all three in sync. UI: `#st-smtpPreferSmtp` toggle (key `m365_smtp_prefer_smtp`), saved/loaded by `scheduler.js`.
|
||||
|
||||
## Scheduler — scan_scheduler.py + routes/scheduler.py
|
||||
|
||||
|
||||
+8
-4
@@ -148,8 +148,12 @@ def smtp_test():
|
||||
"</body></html>"
|
||||
)
|
||||
|
||||
# Try Graph API first
|
||||
if state.connector and state.connector.is_authenticated():
|
||||
# Try Graph API first — unless the user opted to always use SMTP. Graph
|
||||
# returns 202 (queued) even for recipients Exchange later silently drops
|
||||
# (e.g. a Google-hosted subdomain of the O365 domain), so SMTP is the only
|
||||
# reliable path for those; prefer_smtp forces it.
|
||||
prefer_smtp = bool(saved.get("prefer_smtp"))
|
||||
if state.connector and state.connector.is_authenticated() and not prefer_smtp:
|
||||
try:
|
||||
_send_email_graph(subject, body_html, recipients)
|
||||
return jsonify({"ok": True, "method": "graph", "recipients": recipients})
|
||||
@@ -285,8 +289,8 @@ def send_report():
|
||||
"</body></html>"
|
||||
)
|
||||
|
||||
# Try Graph API first
|
||||
if state.connector and state.connector.is_authenticated():
|
||||
# Try Graph API first — unless prefer_smtp is set (see smtp_test for why).
|
||||
if state.connector and state.connector.is_authenticated() and not smtp_cfg.get("prefer_smtp"):
|
||||
try:
|
||||
_send_email_graph(subject, body_html, recipients,
|
||||
attachment_bytes=xl_bytes, attachment_name=fname)
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ def _maybe_send_auto_email():
|
||||
"</body></html>"
|
||||
)
|
||||
|
||||
if state.connector and state.connector.is_authenticated():
|
||||
if state.connector and state.connector.is_authenticated() and not smtp_cfg.get("prefer_smtp"):
|
||||
try:
|
||||
_send_email_graph(subject, body_html, recipients,
|
||||
attachment_bytes=xl_bytes, attachment_name=fname)
|
||||
|
||||
Reference in new issue
Block a user