From dddc48440b0e59b32867dfd1a88fbb1e632e6622 Mon Sep 17 00:00:00 2001 From: ScreenTinker Date: Tue, 12 May 2026 18:34:08 -0500 Subject: [PATCH] docs(readme): document Microsoft Graph email setup + dev restrict + spam protections Replaces the stub EMAIL_WEBHOOK_URL row with the real 5-variable GRAPH_* config table, Azure AD app registration steps (single-tenant + Mail.Send application permission + admin consent), the local-dev stdout-fallback behavior when unconfigured, the optional GRAPH_DEV_RESTRICT_TO allow-list for safe development against fresh prod DB clones, and a brief enumeration of the alert spam protections (2h dedup, 24h long-offline cutoff, sequential send pattern, per-user email_alerts opt-out). Pairs with c71c401 which shipped the implementation. --- README.md | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cf51aff..585b073 100644 --- a/README.md +++ b/README.md @@ -121,15 +121,42 @@ Let users sign in with Microsoft/Azure AD. | `MICROSOFT_CLIENT_ID` | Your Azure AD application client ID | | `MICROSOFT_TENANT_ID` | Tenant ID (`common` for multi-tenant) | -#### Email Alerts +#### Email Alerts (Microsoft Graph) -Send email notifications when devices go offline. +Send email notifications when devices go offline. Backed by Microsoft Graph Mail.Send via the client-credentials flow. | Variable | Description | |----------|-------------| -| `EMAIL_WEBHOOK_URL` | POST endpoint that sends emails. Receives JSON: `{ to, subject, body }` | +| `GRAPH_TENANT_ID` | Microsoft Azure AD tenant ID | +| `GRAPH_CLIENT_ID` | Azure AD app registration client ID | +| `GRAPH_CLIENT_SECRET` | Azure AD app registration client secret | +| `GRAPH_SENDER_EMAIL` | Mailbox to send from (must be a valid mailbox or alias in the tenant) | +| `GRAPH_SENDER_NAME` | Display name shown in the email `From` field (defaults to `ScreenTinker`) | -You can point this at any email sending service (SendGrid, Mailgun, a simple SMTP relay, etc.) via a small webhook adapter. +**Azure AD app setup:** + +1. Register a new app in Azure AD (single-tenant) +2. Under **API permissions**, add an **Application** permission: Microsoft Graph → `Mail.Send` +3. Click **Grant admin consent** for the tenant +4. Under **Certificates & secrets**, generate a new **Client secret** and capture the value (it is only shown once) +5. Capture the **Directory (tenant) ID** and **Application (client) ID** from the Overview page +6. Set the five env vars above in your deployment (systemd unit, `.env` file, etc.) + +**Local dev fallback:** if any of `GRAPH_TENANT_ID`, `GRAPH_CLIENT_ID`, `GRAPH_CLIENT_SECRET`, or `GRAPH_SENDER_EMAIL` is unset, `sendEmail()` short-circuits and logs `[EMAIL] not configured - would send to ...` to stdout instead of calling Graph. The app keeps running normally; only delivery is suppressed. This means a minimal local-dev install with no M365 access works fine — email-triggering features (device-offline alerts, future invite emails) just won't deliver anything externally. + +**Dev safety allow-list:** + +| Variable | Description | +|----------|-------------| +| `GRAPH_DEV_RESTRICT_TO` | Comma-separated allow-list of recipient emails. When set, sends to addresses **not** in the list are suppressed (logged but never posted to Graph). | + +Use this in local dev when running against a fresh production database clone to prevent accidental emails to real users. Leave it **unset in production** so emails flow to everyone normally. + +**Alert spam protections** (also live, no configuration needed): +- **2-hour dedup window** per (alert-type, target-id) pair — the same device won't trigger repeated alerts within two hours +- **24-hour long-offline cutoff** — devices that have been offline for more than 24 hours stop generating alerts (the user already knows or the device is abandoned; further alerts are noise) +- **Sequential send pattern** through the offline-alert backlog — avoids Graph's per-app concurrent-send throttling (HTTP 429 `ApplicationThrottled`) +- **Per-user opt-out** via the `email_alerts` toggle in Settings → Account; respects user preference before any Graph call ### Production Deployment