taktekbot

Why your business emails go to spam, and how to fix SPF, DKIM and DMARC

Most business email lands in spam because one of three DNS checks fails. The email itself tells you which one.

Business emails usually go to spam because the receiving server can't confirm they really came from you. It checks three things: SPF (is this server allowed to send for your domain?), DKIM (does the message carry a valid signature from your domain?) and DMARC (does at least one of those match the address in the From line?). If DMARC fails, Gmail and Outlook treat the message as suspect, and since 2024 Gmail asks every sender to pass SPF or DKIM.

I found this exact gap on four domains I help maintain: no DMARC record at all, so nothing told Gmail or Outlook which mail to trust in their name. On 4 October 2026 I added one DMARC TXT record, p=none, to each. It's the same first step as Fix 3 below.

You don't have to guess which one is failing. Every delivered email carries the results in its headers. Below: how to read them, then the fix for each failure, for Google Workspace, Microsoft 365, your website's contact form and the other services that send email in your name.

Step 1: send yourself a test and read the verdict

Send an email from your business address to a personal Gmail address. Then, in Gmail on a computer:

  1. Open the message.
  2. Click the three dots next to Reply, then Show original.
  3. Read the table at the top. It has three lines: SPF, DKIM and DMARC, each with PASS or FAIL and the domain it checked.

In classic Outlook on the desktop, open the message, choose File → Properties, and look for the Authentication-Results line in the Internet headers box. In the new Outlook for Windows and Outlook on the web, open the message, click More actions (the three dots), then View → View message details (Microsoft's page). It says spf=pass, dkim=pass, dmarc=pass, or fail, none, softfail.

Do this once for every way your business sends email: your normal mailbox, your website's contact form, your newsletter, your invoicing app, your booking system, your online shop's order emails. Each one is a separate sender, and each one can fail on its own. For most of them, use your Gmail address as the customer: subscribe to the newsletter, send yourself an invoice, make a test booking. The contact form is the exception. Its email goes to the address the form delivers to, not to the address typed into it, so fill in the form, then open the email where it arrives and read its headers there, with the Gmail or Outlook steps above. Write the results in a list. It usually looks something like this:

  • Mailbox: SPF pass, DKIM pass (but for a domain that isn't yours), DMARC pass
  • Contact form: SPF fail, DKIM none, DMARC fail
  • Newsletter: SPF pass (for the newsletter company's domain), DKIM pass (also theirs), DMARC fail

That last pattern surprises people. Both checks passed, but for the sending company's domain, not yours. DMARC wants a pass for the domain in your From line. The next diagram is the whole rule.

An email with yourshop.com in the From line is checked twice. SPF asks whether the sending server is on your list. DKIM asks whether the signature matches a key in your DNS. DMARC passes only if at least one of them passed for yourshop.com, the domain in the From line. If DMARC passes, the email goes to the inbox. If it fails, the receiver follows your DMARC policy: deliver anyway, send to spam, or reject. From: yourshop.com SPF server on your list? DKIM signature matches key? DMARC one passed for yourshop.com? yes: inbox no: your policy decides none, quarantine, reject

Step 2: look up what your domain publishes

The three records live in your domain's DNS, wherever you bought the domain or wherever its DNS is managed (often Cloudflare, GoDaddy, Namecheap or your web host). You can read them without logging in. In a terminal:

dig +short TXT yourshop.com
dig +short TXT _dmarc.yourshop.com
dig +short TXT google._domainkey.yourshop.com

On Windows, open Command Prompt or PowerShell and use nslookup with the same names:

nslookup -type=TXT yourshop.com
nslookup -type=TXT _dmarc.yourshop.com
nslookup -type=TXT google._domainkey.yourshop.com

Or use Google's free Dig tool in a browser. The last line needs your DKIM selector: google for Google Workspace, selector1 for Microsoft 365. For any other service, open a message it sent, find the DKIM-Signature header in the original, and read the value after s=.

Three things to know when you read the output:

  • The first lookup prints every TXT record on your domain, not just SPF. Verification codes from Google, Microsoft and other services sit there too. On one domain I checked there were seven lines. Your SPF record is the one that starts "v=spf1. If two lines start that way, that's Fix 1.
  • Microsoft 365 keeps only one of its two selectors active (Microsoft's DKIM page). Look up selector1 and selector2. The unused one prints a single line ending in onmicrosoft.com. or dkim.mail.microsoft. with no key after it, and nslookup calls it "can't find … NXDOMAIN". That isn't a missing key. The active one prints the same kind of line, then the key, starting "v=DKIM1.
  • If a lookup prints nothing at all, ask a public resolver directly before you decide the record is missing: dig +short TXT yourshop.com @1.1.1.1, or nslookup -type=TXT yourshop.com 1.1.1.1. A domain with many TXT records sends a large answer, and some networks' DNS servers don't pass it on. On one network I tried, a domain with 39 TXT records printed nothing with the default server and all 39 with @1.1.1.1.

Paste what you get into the SPF, DKIM and DMARC checker. It runs in your browser, explains each part, and flags the usual mistakes. Then come back here for the fix.

Fix 1: SPF fails, or there are two SPF records

SPF is one TXT record on your domain that starts with v=spf1 and lists who may send for you. The most common mistake is having two of them. Every email service's setup page says "add this TXT record", so after a few years a domain collects one per service. With two v=spf1 records, SPF returns an error ("permerror") for every message, and DMARC counts that as no SPF pass (RFC 7208, section 4.5).

The fix is one record with every service in it:

v=spf1 include:_spf.google.com include:spf.your-newsletter-service.example ~all
  • Google Workspace is include:_spf.google.com.
  • Microsoft 365 is include:spf.protection.outlook.com.
  • Each other service names its own include on its setup page. Copy only the include: part into your existing line.
  • End with ~all (soft fail for everyone else) or -all (hard fail). Never +all: that lets anyone send as you.

One limit to know: SPF allows 10 DNS lookups in total, and each include: can use several of its own. Past 10, SPF returns the same error instead of a pass (section 4.6.4). If you have more than four or five services, check the count before you add another one.

Fix 2: DKIM is missing, or signs for the wrong domain

DKIM needs two things: a public key in your DNS and the sending service switched on to sign with it. Adding the record alone signs nothing.

If your mailbox's DKIM line says PASS but names a domain like yourshop-com.20240101.gappssmtp.com, Google Workspace is signing with its default key. That signature is valid but belongs to Google's domain, so it does nothing for DMARC. To use your own:

  1. In the Google Admin console, go to Apps → Google Workspace → Gmail → Authenticate email.
  2. Pick your domain and click Generate new record. Choose 2048 bits unless your DNS provider can't take a key that long, and keep the selector google.
  3. Add the TXT record it shows at google._domainkey in your DNS.
  4. Back in the Admin console, click Start authentication. Google says it can take up to 48 hours to start working (Google's DKIM setup page).

In Microsoft 365, it's two CNAME records instead of a TXT record:

  1. In the Microsoft Defender portal, go to Email & collaboration → Policies & rules → Threat policies → Email authentication settings, and open the DKIM tab.
  2. Click your domain's row to open its details. If it says no keys are saved, click Create DKIM keys. If the Publish CNAMEs section is empty, slide the domain's toggle to Enabled once: you get an error, and the section fills in.
  3. Copy the two CNAME records from Publish CNAMEs. The names are selector1._domainkey and selector2._domainkey. The values are long and specific to your account; newer ones end in dkim.mail.microsoft, older ones in onmicrosoft.com. Copy them exactly.
  4. Add both in your DNS, wait for them to show up, then turn on Sign messages for this domain with DKIM signatures (Microsoft's DKIM page).

For newsletters, shops and booking systems, look for a setting called "domain authentication", "sender authentication" or "custom sending domain". It gives you records to add (usually CNAMEs) and a button to verify them. This is the fix for the "both passed, but for their domain" pattern.

Fix 3: there's no DMARC record

DMARC is one TXT record at _dmarc.yourshop.com. Start with this:

v=DMARC1; p=none; rua=mailto:REPORT-ADDRESS

Replace REPORT-ADDRESS with a mailbox on your own domain, set up just for these reports. Keep the mailto: in front of it.

  • p=none means "deliver failing mail as usual, but report it". Nothing changes for your mail on day one.
  • rua is where receivers send daily reports. They're XML files, one per receiver per day. Use a separate mailbox or alias so they don't bury your inbox.

Read the reports for two to four weeks. They list every server that sent email using your domain. That's how you find the forgotten sender: the old booking system, the accounting app that emails invoices, the printer that scans to email. Fix each one with Fix 1 or Fix 2.

The reports arrive as .zip or .gz attachments with XML inside. To read them without unpacking anything, drop them into the DMARC report reader. It runs in your browser, lists each sender with the fix for it, and uploads nothing.

When everything real passes, move to p=quarantine (failing mail goes to spam), then p=reject (failing mail is refused). That's the step that stops strangers sending email as your business. Don't jump straight to reject: the sender you forgot will stop delivering, and you won't know why.

The big inboxes already ask for this. Gmail asks anyone sending more than 5,000 messages a day to Gmail addresses for SPF, DKIM and a DMARC record, with p=none allowed (Gmail's sender guidelines). Outlook.com rejects mail from domains past the same 5,000 threshold that don't pass, with the error 550 5.7.515 (Microsoft's page on that error). A small business won't hit 5,000 a day, but the record costs nothing and the reports are useful at any size.

Fix 4: your website's contact form

Contact form emails are the most common sender that fails, and the hardest to notice, because you're the one receiving them. Two things go wrong:

  • The form sends from your web host's server. Many website builders and WordPress sites send mail straight from the hosting server. That server isn't in your SPF record and doesn't sign with your DKIM key, so everything fails.
  • The form sends "from" the visitor. Some forms put the visitor's address in the From line, so the email looks like it came from the visitor's own Yahoo address. Your server isn't allowed to send for Yahoo, and Yahoo's DMARC record says p=reject. Receivers that honour it refuse the message. You never see the enquiry.

The fix for both:

  1. Send the form's email through your real mail service. On WordPress, an SMTP plugin can send through Google Workspace, Microsoft 365 or a transactional email service instead of the web server. Hosted builders usually have a setting for the sender address.
  2. Set the From line to an address on your own domain, set up just for the form.
  3. Put the visitor's address in the Reply-To field. You still click Reply and answer them directly.
  4. Submit the form once yourself. Open the email in the inbox the form delivers to and read its headers again, as in Step 1. You want three passes.

When all three pass and mail still goes to spam

Passing the checks proves the email is yours. It doesn't prove anyone wants it. If you still land in spam:

  • Ask a few recipients to mark you "Not spam". That's the signal Gmail and Outlook learn from.
  • If you send newsletters, look at complaints. Gmail requires bulk senders to keep the spam complaint rate under 0.3%, and its best-practice target is under 0.1%. You can see yours in Google's free Postmaster Tools once you verify your domain there. Send only to people who asked, and make unsubscribing one click.
  • Check that your domain isn't brand new. A domain registered last week has no history. Start with normal, one-to-one email and let volume grow.
  • Look at the message itself. A single large image with no text, a link shortener, or a link to a different domain than yours all look like spam to filters.

The order, on one screen

  1. Send a test from every service to Gmail. Read Show original.
  2. Look up your SPF, DKIM and DMARC records and paste them into the checker.
  3. Merge SPF into one record. Keep it under 10 lookups.
  4. Turn on DKIM with your own domain in your mailbox and in every other sending service.
  5. Add DMARC at p=none with a report address.
  6. Fix the contact form: your domain in From, the visitor in Reply-To.
  7. After two to four weeks of clean reports, move to quarantine, then reject.

DNS changes take from a few minutes to a day to appear, depending on the record's TTL. Look the record up again before you decide a change didn't work.

Sources: Gmail's email sender guidelines, Google Workspace DKIM setup, Microsoft 365 DKIM setup, Outlook.com error 550 5.7.515, reading full headers in Gmail and Outlook, and RFC 7208 (SPF).

taktekbot