Help/Troubleshooting

Markdown

Troubleshooting

Updated Oct 22, 2026 · 5 min read

Pick what you're seeing. Each fix says how to check it and what to do next.


Emails aren't arriving

Start with the email itself. Open it on the Emails page in the dashboard, or look it up by the msg_… id the send returned:

Terminal
groundmail emails get --id msg_abc123

Its status says where it stopped:

Status What it means What to do
scheduled It goes out at scheduled_at Nothing, or reschedule or cancel it
held Held for content review, or sending is paused on the account Held email is reviewed quickly and then sent or rejected; you get a webhook either way
suppressed A recipient is on your suppression list, or Groundmail validation held every recipient back Check details.suppressed or held_back. Remove the suppression only if you know the address works now
failed It was rejected, for example by content scanning Read bounce_reason
sent Accepted for delivery and on its way Wait for delivered or bounced. A slow receiving server can take a few minutes
bounced The receiving server refused it bounce_type says why: hard means the address can't receive (it's suppressed now); block means the server refused the sender, not the address
delivered The recipient's mail provider accepted it It's in their mailbox system: check spam and filters on their side (Going to spam)

The send itself returned an error

Nothing was sent. The error body's code and hint say what to fix: see API errors.

Only your own address gets mail

Sandbox sends (from noreply@mail.groundmail.dev) only go to your account email. To send to anyone else you need a verified domain and a payment method on file at Settings → Billing. The Free plan is never charged.

It's a test send

Sends with a test key (gm_test_…) and sends to @simulator.groundmail.dev addresses run every check but deliver nothing. They're marked test: true. See Testing.


Domain won't verify

Run verify again from the domain's page in the dashboard, or:

Terminal
groundmail domains verify yourdomain.com

The response says which records are missing. Then check these, most common first.

DNS hasn't propagated yet

New records can take a few minutes to show up in public DNS, sometimes longer at some hosts. Wait, then verify again. Re-running verify is always safe.

Two SPF records

A domain can only have one SPF record. If you already send from another service, add include:spf.groundmail.dev to your existing SPF record instead of adding a second one:

DNS
v=spf1 include:_spf.google.com include:spf.groundmail.dev ~all

The record is on the wrong name

DNS hosts handle names differently. Some want the full name (_groundmail.yourdomain.com), others only the part before your domain (_groundmail); entering the full name in the second kind gives _groundmail.yourdomain.com.yourdomain.com. Compare what you added with the names in the dashboard, and make sure the records are in the zone that actually serves your domain.

The DKIM value was split or cut short

The DKIM TXT value is long. Paste it exactly as shown, as one value; some hosts split long values into quoted chunks, which is fine, but a value cut short fails. If your DNS is on Cloudflare, Vercel or GoDaddy, let Groundmail add the records for you instead: see Apply DNS.

Public DNS looks right, but verify still fails

Verify also waits for the mail server to accept the DKIM and return-path records, which can lag behind public DNS. The response shows mail_server_signing.dkim_ok and return_path_ok; wait a few minutes and verify again. Details: Verify DNS.


Going to spam

  1. Send from your own verified domain, not the sandbox sender. Verification turns on DKIM signing with your domain, so DMARC can pass.
  2. Add a DMARC record if your domain has none. Start with p=none and watch the reports with DMARC monitoring.
  3. Keep transactional and marketing apart. Password resets and receipts go out as transactional; onboarding tips and updates as product, which sends from separate IPs. See Transactional and product streams.
  4. Check your bounce and complaint rates on the Deliverability page or with GET /deliverability. Bounces above 2% or complaints above 0.1% hurt inbox placement.
  5. Look at the content. Link shorteners, image-only emails and a mismatched from name all count against you. An email that scores badly in content scanning is held or rejected before it goes out.

API errors

Every error has a stable code, a message, a hint that says how to fix it, and a docs_url. Branch on code, never on message.

Status Usual cause Fix
401 Missing or wrong API key Send Authorization: Bearer gm_… with a key that hasn't been revoked
403 from isn't on a verified domain, a sandbox send to someone other than you, or a key without the scope Read hint. See forbidden and insufficient_scope
400 A missing or invalid field, or invalid JSON Read message and details. Every send needs from, to, subject and html or text
422 A recipient is suppressed or opted out See details.suppressed, details.category_unsubscribed or details.held_back
429 Rate limit, plan limit or the new-account ramp-up rate_limited: back off and retry. plan_limit: upgrade. daily_ramp_limit: send the rest after details.resets_at. See Sending limits
5xx Something failed on our side Retry with backoff and the same Idempotency-Key, so a retry never sends twice

The full list, with what to do for each code: Errors.


Webhooks not arriving

  • Check the endpoint is subscribed to the event. Each endpoint lists the events it gets; email.delivered and email.bounced are separate.
  • Check the signature with the raw body. Verify Groundmail-Signature against the request body exactly as received, before any JSON parsing. See Signature verification.
  • Answer quickly with a 2xx. Do the work after you respond. A delivery that doesn't get a 2xx is retried 4 more times over about 5 minutes.
  • Send a test event with POST /emails/test to see what your endpoint receives, or send to a simulator address to get every event of a real send without delivering mail.

Still stuck?

Use the chat button in the dashboard, or email support@groundmail.dev. Include the msg_… id or the domain name; we can see the rest, so there's no need to send keys or logs.

Was this page helpful?