HomeProjectsBlogContact

Sending Email from Your Web App Without Landing in Spam

Password resets and receipts that end up in spam are a broken product. How transactional email works, SPF, DKIM and DMARC in plain English, and the habits that keep your emails in the inbox.

Sending Email from Your Web App Without Landing in Spam

Your app sends emails that really matter: verification links, password resets, receipts, invitations. If they land in spam, or never arrive at all, users can't sign in, can't pay and assume your product is broken. Email deliverability is one of those unglamorous topics that has a direct effect on revenue.

Transactional vs marketing email

  • Transactional email is triggered by a user's action: "verify your email," "here's your receipt," "reset your password." Users expect it and need it.
  • Marketing email is sent in bulk to many people: newsletters, promotions.

Keep them separate, ideally on different sending subdomains or streams. If a marketing campaign gets spam complaints, you don't want that to hurt your password reset emails.

Don't send from your own server

You can run a mail server, but deliverability depends heavily on the reputation of the sending IP address, and a fresh VPS IP has none (or a bad one inherited from a previous user). Use a transactional email service. Most have free or low-cost tiers for small volumes, simple APIs and the reputation management you'd otherwise have to build.

SPF, DKIM and DMARC in plain English

These three DNS records prove that emails claiming to come from your domain are legitimate. Major mailbox providers increasingly require them, especially for anyone sending at volume.

SPF (Sender Policy Framework) is a TXT record listing which servers may send email for your domain:

v=spf1 include:_spf.youremailprovider.com ~all

You can only have one SPF record per domain. Combine all your senders in it.

DKIM (DomainKeys Identified Mail) adds a cryptographic signature to each email. Your provider gives you a public key to publish as a DNS record, and receivers use it to check that the message wasn't forged or altered.

DMARC ties them together and tells receivers what to do when checks fail:

v=DMARC1; p=none; rua=mailto:dmarc-reports@yourdomain.com

Start with p=none to collect reports without affecting delivery. Once you're confident all your legitimate email passes, move to p=quarantine, then p=reject. (DNS records explained.)

Habits that keep you in the inbox

  • Send from your own domain, never from a free webmail address.
  • Use a real, consistent "From" name and address, like Acme <hello@mail.acme.com>. A noreply@ address is fine for system emails, but a monitored reply address builds trust.
  • Keep emails relevant and expected. Transactional emails should be about the action the user just took.
  • Include a plain-text version alongside HTML.
  • Avoid spammy patterns: all-caps subjects, excessive links, link shorteners, huge images with little text.
  • Make links match your domain. Tracking redirects through unrelated domains look suspicious.
  • Handle bounces and complaints. Stop sending to addresses that hard-bounce or mark you as spam. Your provider reports these through webhooks. (Handling webhooks.)
  • For marketing email, include an easy unsubscribe, including the one-click unsubscribe header that large mailbox providers expect from bulk senders.
  • Warm up new domains gradually if you're going to send at volume.

Send asynchronously

Don't make users wait while your app talks to an email API. Enqueue the email and send it from a background job, with retries if the provider is temporarily unavailable. (Background jobs.)

Design for real inboxes

  • Keep layouts simple: a single column with inline-friendly styles. Email clients support only a subset of modern CSS.
  • Make the main action a clear button, with the link also available as text.
  • Keep it short. Users are skimming on a phone.
  • Test in several clients: Gmail, Outlook and Apple Mail render differently.

Local development

Never send real emails from development or test environments by accident. Use a local mail catcher like Mailpit, which accepts emails over SMTP and shows them in a web interface, or your provider's sandbox mode. (More free tools.)

Security notes

  • Password reset and magic-link emails contain sensitive tokens. Make them expire quickly and single-use. (Secure password resets.)
  • Don't put sensitive personal data in emails unnecessarily; email isn't a secure channel.
  • Rate limit endpoints that trigger emails, or attackers will use your app to spam people. (Rate limiting.)

Troubleshooting checklist

  1. Did your app actually send it? Check your logs and the provider's activity log.
  2. Did it bounce? The provider will show the reason.
  3. Do SPF, DKIM and DMARC pass? Look at the raw headers of a received email; most mail clients have a "show original" option.
  4. Is it in spam? Check the content, links and whether your domain is new or recently had complaints.

FAQ

Why are my emails going to spam?

Common causes are missing SPF, DKIM or DMARC records, sending from a server with poor IP reputation, spam-like content, mismatched link domains and high bounce or complaint rates.

Do I need SPF, DKIM and DMARC?

Yes. Major mailbox providers increasingly require them, and they significantly improve deliverability while protecting your domain from spoofing.

Can I send email from my own VPS?

Technically yes, but new server IPs usually have poor reputation, so emails often land in spam. A transactional email service is far more reliable for most apps.

Keep reading

More from the workbench

All articles →