Send email from your app, with SPF, DKIM and DMARC
Send your app's email through an email provider on port 587 or 465, and add the SPF, DKIM and DMARC records that keep it out of spam, in our DNS editor.
Updated 17 Oct 20264 min read
Your app's emails, like order confirmations and password resets, go through an email provider you choose, such as Mailgun, Postmark, Amazon SES or Brevo. Tanzahost doesn't send them for you yet. Your app talks to the provider on port 587 or 465; port 25 is closed for every app, so no app here can send spam straight to the world.
Then three DNS records tell the receiving side your email is real. Gmail, Yahoo and Outlook check them, and Google requires all three from anyone sending more than 5,000 emails a day to Gmail (Google's sender guidelines).
| Record | What it says | Where it goes |
|---|---|---|
| SPF | Which providers may send email for your domain | A TXT record on the domain itself, @ |
| DKIM | The public half of the key your provider signs each email with | A TXT or CNAME record on a name the provider gives, like pdk1._domainkey |
| DMARC | What to do with email that fails both, and where to send reports | A TXT record on _dmarc |
Asha's shop sends its order emails through Mailgun, from orders@duka.co.tz, and her staff mailboxes are on Google Workspace. Here's her setup.
Step 1: add your domain at the provider
At your email provider, add the domain you send from: duka.co.tz. The provider then shows the records it needs: its SPF part, its DKIM record, and often a record for bounces. Keep that page open.
Step 2: give your app the SMTP details
Open the project's Variables tab, choose your app, and add the provider's SMTP details. For a Laravel app and Mailgun's SMTP:
MAIL_MAILER=smtp
MAIL_SCHEME=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=postmaster@duka.co.tz
MAIL_PASSWORD=…
MAIL_FROM_ADDRESS=orders@duka.co.tz
MAIL_FROM_NAME=DukaOn port 587 the connection starts plain and switches to encryption at once; for port 465 use MAIL_SCHEME=smtps (Mailgun: SMTP). Other frameworks have their own names: in Django, read EMAIL_HOST, EMAIL_PORT and the rest from variables in settings.py. Choose Redeploy when the page says Redeploy to apply.
Step 3: open the DNS editor
If your domain uses our nameservers, its records are on your project's DNS tab. If you connected Cloudflare, the same tab changes the records in your Cloudflare account. If your domain's DNS is somewhere else, add the records there instead: they're the same records.
To add each record, choose Add record, then fill in Type, Name (@ for the domain itself, or the part before it, like _dmarc), Value, and TTL (Automatic is an hour).
Step 4: add SPF
A domain has one SPF record. Every provider that sends for you goes into it, each with its own include:. Mailgun's alone is:
v=spf1 include:mailgun.org ~allAsha also sends from Google Workspace, so her one record names both:
v=spf1 include:_spf.google.com include:mailgun.org ~all| Type | Name | Value |
|---|---|---|
| TXT | @ | v=spf1 include:_spf.google.com include:mailgun.org ~all |
~all asks receivers to treat email from anywhere else with suspicion; -all asks them to refuse it. Two SPF records on the same name make both fail, so if one is there already, change it instead of adding another. Our templates (Google Workspace, Microsoft 365, Zoho Mail) never add a second one either: add their include: to yours by hand. An SPF record may look up at most 10 other names in all, includes inside includes counted (RFC 7208).
Step 5: add DKIM
Copy the DKIM record exactly as your provider shows it: its name and its value are your domain's own. A TXT one looks like this, with a much longer key:
| Type | Name | Value |
|---|---|---|
| TXT | pdk1._domainkey | v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA… |
The part before ._domainkey is the key's name, its selector (RFC 6376). Paste the value as one line. If your provider shows it as several quoted pieces, like "v=DKIM1; k=rsa; " "p=MIIB…", paste them as they are: the editor joins them. A TXT value may be up to 2,000 characters. If the provider gives a CNAME instead, add a CNAME with its name and value.
Step 6: add DMARC
Start by watching only, with reports sent to a mailbox you read:
| Type | Name | Value |
|---|---|---|
| TXT | _dmarc | v=DMARC1; p=none; rua=mailto:dmarc@duka.co.tz |
p=none changes nothing for your email; receivers send daily reports to the rua address, saying what passed and what didn't. After a few weeks of clean reports, ask them to act on what fails:
v=DMARC1; p=quarantine; rua=mailto:dmarc@duka.co.tzp=quarantine sends failing email to spam, and p=reject refuses it. An email passes DMARC when SPF or DKIM passes for the same domain as its From address (RFC 7489, dmarc.org).
Step 7: check it works
In the DNS editor, each record shows "The internet sees this record" once it's out. Ours answer within a minute.
At your provider, press its check or verify button.
Send an email from your app to a Gmail address. In Gmail, open it, choose Show original, and look for
SPF: PASS,DKIM: PASSandDMARC: PASS.
If SPF fails, the provider is missing from your one SPF record. If DKIM fails, compare the record's name and value with the provider's, character by character. Changing SPF can send your emails to spam until it's right again, so change it when you can check it straight away.