Content scanning and held emails
Groundmail scans the content of outgoing and incoming email for spam. Outgoing scanning protects the sending IPs your mail shares with other customers; incoming scanning gives every received email a spam score you can act on.
Outgoing email
Every email sent from a Groundmail mail server is scored before it leaves. A score is the sum of many content checks (suspicious links, phishing patterns, known spam phrases, broken formatting). Normal transactional and product email scores well under 5.
| Who | What happens over the limit | Limit (transactional / product) |
|---|---|---|
| Accounts new to sending (the first stages of the ramp-up, or new Free accounts), and accounts we are reviewing | The email is held for review before it is sent | 12 / 7 |
| Every account | The email is rejected and never sent | 30 / 15 |
Transactional email (the default category) has a higher limit than product email, so sign-in codes and receipts are not stopped by a borderline score.
Held emails
A held email has status held:
POST /emailsreturns"status": "held"instead ofsuccess.- The email shows Held on the Emails page.
- An
email.heldwebhook is sent withheld_reasonandspam_score.
We review held emails quickly. Released email is sent as usual and you get email.delivered (or a bounce). Rejected email is never sent and you get email.failed with the reason in bounce_reason.
An email can also be held while sending is paused on your account. It goes out when sending resumes.
Rejected emails
An email over the rejection limit gets status failed, an email.failed webhook, and a bounce_reason like Rejected by content scanning: spam score 31.2 is at or over the limit of 30. The recipient is not added to your suppression list: the address did nothing wrong.
Repeated holds or rejections in a day pause sending on the account while we look at it, the same way a high bounce rate does.
Avoid false positives
- Send from a domain with SPF, DKIM and DMARC set up (Groundmail sets these up when you verify a domain).
- Include a plain-text version, and keep HTML well formed.
- Link to your own domain, not URL shorteners.
- Avoid all-caps subjects, piles of exclamation marks and image-only email.
If a legitimate email was held or rejected, reply to the notification or write to support with the email id (msg_…).
Incoming email
Email received on an inbound domain carries two fields, on the received email and in the email.received webhook:
| Field | Values |
|---|---|
spam_score |
A number. Higher is more likely spam; most clean mail scores under 5. null when the message was not scanned. |
spam_status |
clean (under 5), suspicious (5 up to the spam threshold), spam (at or over the threshold, 10 by default). null when not scanned. |
Filter spam per domain
Set a threshold and an action on the domain:
curl -X PATCH https://api.groundmail.dev/domains/$DOMAIN_ID \
-H "Authorization: Bearer $GROUNDMAIL_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"inbound_spam_threshold": 8, "inbound_spam_action": "drop"}'await groundmail.domains.update('example.com', {
inbound_spam_threshold: 8,
inbound_spam_action: 'drop',
})groundmail domains update example.com --inbound-spam-threshold 8 --inbound-spam-action dropinbound_spam_action: "flag"(the default) keeps the email and marks itspam_status: "spam".inbound_spam_action: "drop"discards email at or over the threshold: nothing is stored and no webhook is sent.inbound_spam_threshold: nullgoes back to the default (10) and drops nothing.