Magic-Mail — Troubleshooting
OAuth token expired
Symptoms: Gmail, Microsoft 365, or Yahoo accounts suddenly fail with "Invalid grant" or "Token expired" after weeks/months of working.
Cause: OAuth refresh token revoked (password change, consent screen update, 6-month inactivity window for Google unverified apps).
Fix:
- Admin → Magic-Mail → Email Accounts.
- Click the account showing the error.
- Click Re-authorize.
- Complete the OAuth consent flow again.
To prevent:
- Set up Google Cloud app verification (removes the 7-day refresh-token expiry for unverified apps).
- Enable offline access scope (
access_type=offline, which Magic-Mail does by default). - Monitor the Email Logs — the first "invalid_grant" error is a signal to re-auth before all emails start failing.
Emails not sending at all
Symptoms: send() returns NO_ACCOUNT_AVAILABLE or Email Logs show no entries.
Run through this checklist in order:
- Plugin enabled?
config/plugins.tsmust have'magic-mail': { enabled: true }. - Admin sidebar shows Magic-Mail? If not, rebuild:
npm run build && npm run develop. - At least one account configured? Admin → Email Accounts.
- Account is marked Active? Disabled accounts are skipped.
- Account passes the Test button? Click it. If it fails, fix the credentials before anything else.
- Routing rules match? If you created rules, make sure at least one rule's condition matches your email. Test with the Test Rule button.
SMTP connection refused
Symptoms: ECONNREFUSED, ETIMEDOUT, or "greeting timed out" errors.
Fix:
- Verify host and port from your provider's docs. Most use
smtp.example.com:587(STARTTLS) or:465(SSL). - Firewall: Outgoing port 587 (or 465) must be open. On cloud hosts (AWS EC2, GCP, Azure) port 25 is often blocked — avoid it.
- TLS settings:
- Port 587 →
secure: falsein account config (uses STARTTLS). - Port 465 →
secure: true.
- Port 587 →
- Gmail SMTP specifically: use an App Password (not your Google password). Generate at myaccount.google.com/apppasswords.
403 Forbidden from SendGrid
Symptoms: SendGrid account returns {"errors":[{"message":"Unauthorized","field":null,"help":null}]}.
Fix:
- Verify the API key is not revoked in the SendGrid dashboard.
- Ensure the API key has Mail Send permission (scoped keys: grant
mail.send, full access works too). - From-address verification: the address you use as
frommust be verified under Sender Authentication → Single Sender Verification (or Domain Authentication for*@yourdomain.com). - Regenerate a new key and re-enter it in Magic-Mail.
Rate limit hit
Symptoms: Error code RATE_LIMITED, emails pile up.
Fix:
- Check Admin → Email Logs — which account is at 100%?
- Adjust the account's rate limits if provider allows higher (Admin → Email Accounts → Edit → Rate Limits).
- Add a fallback chain in the routing rule so overflow goes to a second account.
- Add another account (e.g. second Gmail, or a SendGrid/Mailgun for volume).
- Spread marketing campaigns over time (don't send 10k emails in 1 minute).
Magic-Mail not intercepting Strapi emails
Symptoms: strapi.plugin('email').service('email').send(...) uses the original provider instead of Magic-Mail.
Causes and fixes:
- Plugin order: Magic-Mail must be present in
config/plugins.ts. It registers a hook that overrides the email service on startup. - Conflicting provider: If you have
@strapi/provider-email-sendgridor similar set as the email provider inconfig/plugins.ts, remove it. Magic-Mail replaces the need for provider plugins. - Rebuild required: After install or config change, run
npm run build && npm run develop. - Multiple instances: In multi-instance deployments, ensure all nodes have Magic-Mail installed.
Attachments not working
Provider support varies:
| Provider | Attachments |
|---|---|
| Gmail / Microsoft 365 / Yahoo | Full (up to 25 MB) |
| SMTP | Full (server-dependent) |
| SendGrid | Encoded in JSON body, up to 30 MB |
| Mailgun | Limited (10 MB, sometimes flaky) |
Fix: For attachment-heavy emails, route through Gmail / Microsoft / SMTP. Set a routing rule with condition like attachments && attachments.length > 0 (if your use case supports it), or force the account:
await strapi.plugin('email').service('email').send({
...payload,
accountName: 'Gmail OAuth', // Guaranteed attachment support
});Emails delivered to spam
Common causes and fixes:
- Missing SPF record: Add a DNS TXT record
"v=spf1 include:_spf.google.com ~all"(adjust for your provider). - Missing DKIM: OAuth providers do this automatically. For SMTP, generate DKIM keys in your mail server.
- Missing DMARC: Add
_dmarc.yourdomain.comTXT record"v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com". - From-address mismatch: Match your
fromheader to the authenticated account. - Poor content: Avoid spammy words, broken images, or mostly-image emails.
- Warm-up new accounts: New accounts (especially SendGrid/Mailgun) need gradual volume ramp-up.
Use mail-tester.com to score a test email before sending a campaign.
Enable debug mode
DEBUG=magic-mail:* npm run developLogs every routing decision, account selection, rate-limit check, and send attempt to the terminal.
Or enable in config:
'magic-mail': {
enabled: true,
config: { debug: true },
}Check Email Logs
The single best diagnostic tool is Admin → Magic-Mail → Email Logs:
- Shows every send attempt with timestamp, recipient, account used, status, response time.
- Click an entry to see full error details and raw provider response.
- Filter by date, account, type, or status.
Reset the plugin (nuclear option)
Only in development, never in production:
rm -rf .cache node_modules/.cache dist
npm run build
npm run developTo also wipe account data (development only):
-- Caution: destroys all Magic-Mail data
TRUNCATE TABLE magic_mail_accounts;
TRUNCATE TABLE magic_mail_routing_rules;
TRUNCATE TABLE magic_mail_templates;
TRUNCATE TABLE magic_mail_logs;Still stuck?
- FAQ →
- GitHub Issues
- Email support: support@magicdx.dev
- Discord: discord.strapi.io