← All case files

Case 008 · Online shop · Order emails

Google Workspace went live. Order emails stopped arriving.

A new SPF record left out the web host, so order confirmations land in spam or bounce.

A dark laptop showing a spam folder with the row “Order #2093 confirmed” tagged Spam in red.
Before
Order confirmations land in spam or bounce.
After
SPF merged, DKIM on; inbox checked every few minutes.

The bug

An online shop sends its order confirmations from its web host’s mail server, as orders@shop.example. Then the owner moves company email to Google Workspace and, following the setup guide, publishes an SPF record that lists only Google. From now on the web host isn’t allowed to send mail for shop.example, and it never had DKIM. Since February 2024, Gmail has required every sender to pass SPF or DKIM.

How it shows up

It starts on the day of a change that seems to have nothing to do with orders. Checkout works and payments arrive. The confirmations land in spam or bounce. Customers write in to ask whether their order went through, and some order a second time to be sure. Nobody connects any of it to the email move.

How a test finds it

Place a test order every few minutes and send its confirmation to a Gmail inbox the test controls. Check that the email lands in the inbox, not in spam, and read its Authentication-Results header. If neither spf=pass nor dkim=pass is there, the test fails within minutes of the DNS change.

The fix

Merge the SPF record so it includes both senders, Google and the web host. Turn on DKIM for the web host, or move order emails to a transactional email provider with a verified domain. Add a DMARC record so failures get reported.

The test that catches it

A synthetic order every few minutes, sent to a seeded Gmail inbox, asserting that the confirmation arrives in the inbox and that Authentication-Results shows spf=pass or dkim=pass. It runs around the clock, so a DNS change is caught on the day it’s made.

order-email.check.tsIllustrative
import { test, expect } from "@playwright/test";
import { placeTestOrder, seededInbox } from "./flow";

// Runs every few minutes, around the clock.
test("the confirmation reaches the inbox, authenticated", async ({ page }) => {
  const order = await placeTestOrder(page, { email: seededInbox.address });
  const mail = await seededInbox.waitFor({ subject: order.number });

  expect(mail.folder).toBe("INBOX");
  const auth = mail.headers["authentication-results"];
  expect(auth).toMatch(/spf=pass|dkim=pass/);
});

What it puts at risk

Order confirmations, duplicate orders, a support inbox full of “did my order go through?”, and the trust of customers in a shop that went quiet after they paid.

Tell us what you’re shipping.

An app, a rewrite, an AI agent, an automation, or a release that needs testing. A free 30-minute call, then a price in writing. If you don’t need us yet, we’ll say so.

Book a free call