| name | send-transactional-email |
| description | Ships reliable transactional email (password resets, receipts, verification, alerts) where the hard part is deliverability, not the API call — authenticate the From domain with SPF/DKIM/DMARC alignment, send through a provider (SES/Postmark/SendGrid/Resend/Mailgun) instead of a cold self-hosted MTA, isolate transactional from marketing streams, build inlined-CSS multipart emails, send idempotently via a job runner, and process bounce/complaint webhooks into a suppression list so mail actually lands in the inbox. |
| when_to_use | Sending or fixing delivery of transactional email — auth/verification/reset/receipt mail landing in spam, domain authentication (SPF/DKIM/DMARC), bounce/complaint handling, suppression lists, or rendering. Distinct from implement-push-notifications (the mobile/web PUSH channel, a different transport entirely) and message-queue-jobs (the async job system that ENQUEUES the send and owns retry/DLQ — this skill owns the email-specific deliverability, content, and feedback loop). |
When to Use
Reach for this skill when the work is getting a transactional email into the inbox and reacting to what bounces — domain auth, provider routing, content, and the feedback loop:
- "Password-reset / verification emails are landing in spam (or vanishing) — fix deliverability"
- "Set up SPF / DKIM / DMARC so our From domain authenticates and aligns"
- "Pick and wire a provider (SES, Postmark, SendGrid, Resend, Mailgun) for receipts/alerts"
- "Our marketing blasts are tanking password-reset delivery — separate the streams"
- "Process bounce + complaint webhooks and stop re-sending to dead addresses"
- "Build the email so it renders right in Outlook/Gmail/dark mode with a plain-text fallback"
- "A retry double-sent the receipt / verification email — make sends idempotent"
NOT this skill:
- The async job/queue that enqueues the send, owns retry-with-backoff, DLQ, poison-message handling → message-queue-jobs (this skill is what runs inside that job)
- The idempotency-key store/dedup primitive that makes the enqueue+send exactly-once → idempotency-keys
- Mobile/web PUSH notifications (APNs/FCM/Web Push) — a different transport, not email → implement-push-notifications
- The raw DNS record mechanics (TTL, zone editing, how a TXT/CNAME is published) → configure-dns-tls (this skill tells you which records; that skill publishes them)
- Tracking-pixel/open-tracking consent, unsubscribe-data handling, PII retention/erasure → map-privacy-data-gdpr
- Throttling how many emails one user can trigger → rate-limiting
- Marketing campaigns, newsletters, drip sequences, segmentation → (out of scope — a different sending stream entirely; see step 3)
This skill owns domain authentication, provider/stream choice, email content, idempotent sending, and feedback processing. It hands the actual job-running to message-queue-jobs.
Steps
-
Authenticate the sending domain — this is the gate, not optional. Gmail/Yahoo require SPF + DKIM + DMARC on bulk and increasingly on all mail; without alignment you go to spam or get rejected. Publish all three on the From domain (records owned by configure-dns-tls; values below). Use a dedicated subdomain like mail.example.com / txn.example.com so reputation is scoped.
| Record | Where | Value (shape) | Purpose |
|---|
| SPF | TXT at sending domain | v=spf1 include:amazonses.com ~all (one TXT, ≤10 DNS lookups, ~all not -all until verified) | authorizes the provider's IPs in Return-Path |
| DKIM | provider-given CNAMEs (SES, Resend) or TXT (<sel>._domainkey) | provider publishes the public key; mail is signed d=example.com | cryptographic signature, survives forwarding |
| DMARC | TXT at _dmarc.example.com | v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=s; aspf=s | tells receivers what to do on auth fail + reports |
Alignment is the part people miss: DMARC passes only if SPF or DKIM passes and its domain matches the visible From: domain. Return-Path: bounces@provider.com aligning SPF to the provider does not align to your From — so DKIM d= must equal your From domain. Set a custom Return-Path / MAIL FROM subdomain (bounce.example.com) at the provider for SPF alignment too. Roll DMARC p=none → monitor rua reports for 1–4 weeks → p=quarantine → p=reject. Never start at reject; you'll blackhole your own mail.
-
Send through a reputable provider — do NOT run your own SMTP MTA on cold IPs. A fresh cloud IP has zero reputation and is often already on a blocklist; running Postfix yourself means you own PTR, warmup, FBL enrollment, and blocklist fights. Use a provider:
Verify
- Auth passes and aligns: send to
check-auth@verifier.port25.com or mail-tester.com — SPF pass, DKIM pass with d= your From domain, DMARC pass with alignment. dig TXT _dmarc.example.com shows the policy; dig TXT <sel>._domainkey.example.com resolves.
- DMARC ramped safely:
rua aggregate reports show your legit mail passing for 1–4 weeks at p=none before you move to quarantine/reject.
- Streams isolated: a forced complaint/bounce on the marketing stream does not appear in or degrade the transactional stream's reputation/dashboards.
- Renders everywhere: the HTML shows correctly in Gmail, Outlook (Word engine), Apple Mail, and dark mode; with images blocked the email is still actionable (alt text, text link); a
text/plain part exists and is non-empty.
- Idempotent: trigger the same logical email twice (or force a job retry) → exactly one message is delivered; the second is a no-op.
- Feedback loop works: send to a provider seed/simulator bounce + complaint address → webhook fires, the address lands in the suppression table, and a subsequent send to it is skipped before hitting the provider.
- Unsubscribe one-click: a POST to the
List-Unsubscribe URL unsubscribes with no extra step; Gmail shows the unsubscribe affordance.
- No real mail from non-prod: staging/CI sends are captured by Mailpit/MailHog/sandbox and cannot reach a real inbox; a deliberate "send to a real address" from staging is blocked.
- Reputation green: Google Postmaster shows domain reputation High/Medium, complaint rate < 0.1%, no blocklist entries.
Done = the From domain passes SPF/DKIM/DMARC with alignment (DMARC ramped p=none→quarantine→reject on real report data), transactional mail goes through a provider on a stream isolated from marketing, emails render with inlined CSS + a plain-text part, sends are idempotent under retry, bounces/complaints flow into a suppression list that the send path honors, and no staging environment can email a real user.