Send Transactional Email
Send verification, password reset, and receipt emails from a backend, and get them delivered instead of spam-foldered.
This guide covers sending transactional email (verification, password reset, receipts) from a backend, and the deliverability mistakes that land mail in spam.
Quick Answer
Send transactional email from your server using a provider like Resend, SendGrid, or SES (not raw unauthenticated SMTP from an app server), verify your own sending domain with SPF, DKIM, and DMARC records, and fire sends best-effort so a slow email provider never blocks the API response.
1. Choose a Provider
Popular options: Resend, SendGrid, AWS SES, or a generic SMTP relay. All work similarly: an API key on the server, a "from" address, and a template or raw HTML/text body. Never call SMTP directly from a mobile app; email always goes through your backend.
2. Verify Your Own Sending Domain
Most providers give you a shared sandbox sender (e.g. onboarding@resend.dev) for quick testing, but production email should send from a domain you own. Verify it in your provider's dashboard, which typically means adding DNS records:
- SPF authorizes the provider's servers to send on your domain's behalf;
- DKIM cryptographically signs outgoing mail so receivers can confirm it wasn't altered;
- DMARC tells receiving mail servers what to do if SPF/DKIM checks fail.
Skipping these is the single biggest reason transactional email lands in spam or gets rejected outright by major providers like Gmail.
3. Send Best-Effort, Not Blocking
Don't make an HTTP response wait on the email provider's API call. If a signup succeeds but the welcome email send times out, the user shouldn't see a failed signup; log the email failure and let the request succeed.
4. Development Fallback
A common pattern: if no API key is configured, log the email content to the console instead of sending it, so local development works without a real provider account or accidentally emailing real addresses during testing.
Common Issues
Emails work in testing, land in spam in production the sending domain isn't verified (missing SPF/DKIM/DMARC), or you're still sending from the provider's shared sandbox domain.
Provider only delivers to your own verified test addresses most providers' sandbox/trial mode restricts delivery to addresses you've manually verified; this is expected until you verify a domain and move off the sandbox.
Signup requests are slow or time out the request handler is awaiting the email send synchronously; fire it without blocking the response.
Password reset emails never arrive but no error is logged check whether the provider silently rejected the send due to an unverified domain; some providers return a 200 even when the message doesn't get delivered.
Verification Checklist
- email sends go through a backend provider, never directly from the app;
- the sending domain has SPF, DKIM, and DMARC records configured;
- email failures don't block the triggering API response;
- a test email to a real inbox (not just the provider's dashboard log) lands outside spam;
- local development has a console-log fallback so it works without provider credentials.