Drupal7 min read

Drupal email going to spam: diagnose and fix with seed tests

Drupal's default mail_system uses PHP mail from the web host. Unauthenticated, shared IP, no DKIM — near-guaranteed spam placement. Here is the full diagnostic and fix path.

Drupal powers a lot of government, university and mid-market sites. These are exactly the places where a password reset email ending up in spam is a real problem: users cannot recover their accounts, support tickets pile up, and the site gets blamed. In nearly every case the root cause is the same — Drupal is still sending mail via PHP mail() from the web host, and in 2026 that combination almost guarantees spam placement.

This article walks through the Drupal mail pipeline, why the default fails, and the two mainstream fixes: the SMTP module for a standard transactional provider, or the Mailgun module (or equivalent) for API-based sending. It ends with a seed-test you can run in twenty minutes.

The quick answer

Install the smtp module (or Mailgun / Sendgrid / SES module), point it at an authenticated provider, publish SPF + DKIM + DMARC for the From domain, then seed-test user registration, password reset and contact form. Each template scans differently — test them all.

How Drupal sends mail

Drupal routes all outbound mail through the mail_system service, which on a fresh install points at PhpMail. That class is a thin wrapper around PHP's mail() function. Every core module that sends — user registration, password reset, contact form, comment notifications — and every contrib module that sends — Webform, Commerce, Group — all hand off to the same service.

Swapping the mail_system implementation once swaps mail for the entire site. That is the elegant part. The ugly part is that the default implementation is PHP mail.

The default PHP mail path, failing in three ways

  1. Unauthenticated sending IP. PHP mail hands the message to the host's local MTA (Postfix, Exim, sendmail). It leaves from the host's IP — usually shared with many other sites.
  2. No SPF alignment. Your From domain's SPF record (if any) does not include the host's IP. SPF result at Gmail: softfail or none.
  3. No DKIM. PHP mail does not sign messages. DKIM result: none. With SPF not passing, DMARC evaluation also fails.

Gmail, Outlook and Yahoo all treat unauthenticated mail from shared hosts as low-trust by default. For transactional content (password resets, account confirmations) that trust signal matters a lot, because the recipient rarely has a prior open/reply history with your domain.

Symptoms
  • Password reset emails "do not arrive" for Gmail users but do arrive for colleagues on the same corporate Exchange.
  • New registrations stall at confirmation. Users email support.
  • Webform submissions trigger notifications that land in the site-owner's Junk folder.
  • drush core:requirements looks clean; the site has no errors — just silent spam.

Two fixes: SMTP module or Mailgun module

Both approaches work. Pick based on which sending provider you plan to use.

Option A: SMTP module + any SMTP provider

The contrib SMTP Authentication Support module (project name: smtp) replaces mail_system with an authenticated SMTP sender. It works with any provider that speaks SMTP.

  1. Install: composer require drupal/smtp, then enable: drush en smtp.
  2. Go to Configuration → System → SMTP Authentication Support.
  3. Set Turn this module on or off to On.
  4. Fill in the SMTP Server (e.g. smtp.postmarkapp.com), SMTP Port (587), protocol (TLS), and username/password from your provider.
  5. Set From Email (e.g. noreply@yoursite.org) and From Name in the E-mail options section.
  6. Use Send test e-mail at the bottom of the same page.

See the companion article Drupal SMTP Module + Inbox Placement for the full walkthrough with provider-specific credentials.

Option B: Provider-native module (Mailgun, SendGrid, SES)

The Mailgun, SendGrid Integration and SES Mailer modules use the provider's API instead of SMTP. Upsides: better error reporting, no open SMTP port needed, often easier for containerised hosts. Downsides: the module ties you to one provider.

  1. Install: e.g. composer require drupal/mailgun, enable, and add an API key from the provider.
  2. The module automatically takes over mail_system for its keys once configured.
  3. Test with the module's built-in test form, or from the Drupal contact form.

DNS: SPF, DKIM, DMARC

A correct transactional setup for yoursite.org looks like:

; SPF — single TXT
yoursite.org.         IN  TXT  "v=spf1 include:mailgun.org ~all"

; DKIM — CNAME to the provider (example: Mailgun)
s1._domainkey.yoursite.org.  IN  CNAME  s1._domainkey.mg.yoursite.org.
; Provider gives you a longer DNS record they publish on their side.

; DMARC
_dmarc.yoursite.org.  IN  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@yoursite.org; adkim=r; aspf=r"

Wait for propagation, then resend the Drupal test mail to a Gmail address. Open the message, "Show original", confirmSPF: PASS, DKIM: PASS, DMARC: PASS.

Drupal integration in beta

A native Drupal extension is in private beta — schedule placement tests from admin and alert on drops.

→ Join the beta waitlist

Seed-test the real templates

The module test email is trivial. Your real Drupal templates — user registration, password reset, contact form notification, Webform results — scan differently.

  1. Generate 20+ seed addresses at check.live-direct-marketing.online covering Gmail, Outlook, Yahoo, Mail.ru, Yandex, GMX, Web.de and ProtonMail.
  2. Register a new account using the first seed. Watch the confirmation email fan out to the panel, with per-provider placement.
  3. Trigger a password reset. Different content, different result — test separately.
  4. Submit the contact form from a seed. Check how the notification lands at the admin mailbox.

Aim for 95%+ inbox across consumer providers. Below 80% and something is still wrong — usually DNS alignment or a DKIM selector mismatch.

FAQ

SMTP module vs Mailgun module — which should I pick?

SMTP module is provider-agnostic, so you can swap providers without changing code. Mailgun / SendGrid modules give better visibility into sending events via the provider API. If you expect to stay with one provider for years, the native module is slightly nicer. Otherwise SMTP is safer.

My Drupal site uses PrivateTempStore for password reset tokens. Does SMTP affect that?

No. Token generation happens inside Drupal, independent of transport. The SMTP module only replaces the transport that delivers the email containing the token. Tokens remain valid for the same timeout regardless of how the email is delivered.

Can I still use Drush to test mail after installing SMTP?

Yes. drush php:eval or drush core:mail both route through the configured mail_system, so a drush-triggered mail uses your SMTP config. Useful for scripted smoke tests in CI.

What about Symfony Mailer support in Drupal 10+?

Drupal 10 ships Symfony Mailer as an optional core experimental and there is a contrib module that wires it to transports cleanly. If you are on Drupal 10.3+, Symfony Mailer is a modern alternative to the SMTP contrib module, with better attachment handling and DSN-style config. Functionally both solve the same spam-fix problem.
Related reading

Check your deliverability across 20+ providers

Gmail, Outlook, Yahoo, Mail.ru, Yandex, GMX, ProtonMail and more. Real inbox screenshots, SPF/DKIM/DMARC, spam engine verdicts. Free, no signup.

Run Free Test →

Unlimited tests · 20+ seed mailboxes · Live results · No account required