From 4a81fa5c87c6e08b655df5fe2bbb57a12840b38d Mon Sep 17 00:00:00 2001 From: Mark Kraakman Date: Wed, 21 Oct 2026 15:34:09 +0200 Subject: [PATCH 1/3] Docs: which inbound messages AhaSend rejects (routing) --- integrations/routing.mdx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/integrations/routing.mdx b/integrations/routing.mdx index a4462e3..151b46d 100644 --- a/integrations/routing.mdx +++ b/integrations/routing.mdx @@ -59,6 +59,23 @@ This functionality enables you to: **MX Record Requirement:** Message routing requires your domain's [MX records from your domain details](/domains) to point to AhaSend. Without proper MX configuration, AhaSend cannot receive emails sent to your domain. +## Which Inbound Messages Does AhaSend Reject? + +AhaSend checks every message that arrives at `mx.ahasend.com` before it is queued for your route. A message that fails a check is refused during the SMTP transaction with a permanent error, so the sending server returns it to the sender as a bounce and nothing reaches your endpoint. The checks, with the SMTP reply the sender's server gets: + +| Check | SMTP reply | What it means | +|---|---|---| +| Neither domain is ours | `556` | No AhaSend account owns the recipient's domain or the sender's domain. Usually a typo in the address, or a domain whose MX points to AhaSend without being added to an account. | +| Not exactly one `From` address | `550` | The message has no `From` header, or more than one address in it. | +| Fails the sender's DMARC policy | `550` | The `From` domain publishes `p=reject` or `p=quarantine`, and neither SPF nor DKIM aligns with that domain. | +| No SPF or DKIM pass | `550` | The `From` domain has no DMARC record, or one with `p=none`, and the message has neither a passing SPF result nor a valid DKIM signature for any domain. | +| Bare line endings | `552` | Lines end in LF instead of CRLF, which the SMTP standard requires. Typical of a script that writes the message by hand. | +| Larger than 20 MiB | `552` | The whole message, attachments included after base64 encoding. See [SMTP limits](/smtp). | + +The authentication checks protect your endpoint: a message that passes them was sent by a server the `From` domain authorizes, so a route cannot be used to feed forged mail into your application. They also mean that mail from a domain with no SPF, no DKIM and no DMARC is refused; if a sender you need mail from is set up that way, they have to publish at least SPF or DKIM, which they need for Gmail and Microsoft anyway. + +A rejected message is not stored and does not appear in your message log; the sender's bounce is the only record. Messages that pass are delivered to your route as described below. + ## Delivery Limits AhaSend makes 12 attempts over about 11 hours, including the first attempt. Each attempt times out after 5 seconds. After more than 100 consecutive failed attempts, the route is disabled and account users are emailed. See [route retry policy](/api-reference/webhooks/retry-policy) and [security](/api-reference/webhooks/security). From a69ddf5d65e14fd42b3061651d7e2a624ea9725e Mon Sep 17 00:00:00 2001 From: Mark Kraakman Date: Wed, 21 Oct 2026 15:47:05 +0200 Subject: [PATCH 2/3] Docs: inbound rejections as a troubleshooting accordion instead of a top-level section --- integrations/routing.mdx | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/integrations/routing.mdx b/integrations/routing.mdx index 151b46d..59206e3 100644 --- a/integrations/routing.mdx +++ b/integrations/routing.mdx @@ -59,23 +59,6 @@ This functionality enables you to: **MX Record Requirement:** Message routing requires your domain's [MX records from your domain details](/domains) to point to AhaSend. Without proper MX configuration, AhaSend cannot receive emails sent to your domain. -## Which Inbound Messages Does AhaSend Reject? - -AhaSend checks every message that arrives at `mx.ahasend.com` before it is queued for your route. A message that fails a check is refused during the SMTP transaction with a permanent error, so the sending server returns it to the sender as a bounce and nothing reaches your endpoint. The checks, with the SMTP reply the sender's server gets: - -| Check | SMTP reply | What it means | -|---|---|---| -| Neither domain is ours | `556` | No AhaSend account owns the recipient's domain or the sender's domain. Usually a typo in the address, or a domain whose MX points to AhaSend without being added to an account. | -| Not exactly one `From` address | `550` | The message has no `From` header, or more than one address in it. | -| Fails the sender's DMARC policy | `550` | The `From` domain publishes `p=reject` or `p=quarantine`, and neither SPF nor DKIM aligns with that domain. | -| No SPF or DKIM pass | `550` | The `From` domain has no DMARC record, or one with `p=none`, and the message has neither a passing SPF result nor a valid DKIM signature for any domain. | -| Bare line endings | `552` | Lines end in LF instead of CRLF, which the SMTP standard requires. Typical of a script that writes the message by hand. | -| Larger than 20 MiB | `552` | The whole message, attachments included after base64 encoding. See [SMTP limits](/smtp). | - -The authentication checks protect your endpoint: a message that passes them was sent by a server the `From` domain authorizes, so a route cannot be used to feed forged mail into your application. They also mean that mail from a domain with no SPF, no DKIM and no DMARC is refused; if a sender you need mail from is set up that way, they have to publish at least SPF or DKIM, which they need for Gmail and Microsoft anyway. - -A rejected message is not stored and does not appear in your message log; the sender's bounce is the only record. Messages that pass are delivered to your route as described below. - ## Delivery Limits AhaSend makes 12 attempts over about 11 hours, including the first attempt. Each attempt times out after 5 seconds. After more than 100 consecutive failed attempts, the route is disabled and account users are emailed. See [route retry policy](/api-reference/webhooks/retry-policy) and [security](/api-reference/webhooks/security). @@ -773,6 +756,23 @@ The workflow functions below use application-owned callbacks such as `createSupp ``` + + AhaSend checks every message that arrives at `mx.ahasend.com` before it is queued for your route. A message that fails a check is refused during the SMTP transaction with a permanent error, so the sender's server returns it as a bounce and nothing reaches your endpoint. The bounce text quotes our reply: + + | Check | SMTP reply | What it means | + |---|---|---| + | Neither domain is ours | `556` | No AhaSend account owns the recipient's domain or the sender's domain. Usually a typo in the address, or a domain whose MX points to AhaSend without being added to an account. | + | Not exactly one `From` address | `550` | The message has no `From` header, or more than one address in it. | + | Fails the sender's DMARC policy | `550` | The `From` domain publishes `p=reject` or `p=quarantine`, and neither SPF nor DKIM aligns with that domain. | + | No SPF or DKIM pass | `550` | The `From` domain has no DMARC record, or one with `p=none`, and the message has neither a passing SPF result nor a valid DKIM signature for any domain. | + | Bare line endings | `552` | Lines end in LF instead of CRLF, which the SMTP standard requires. Typical of a script that writes the message by hand. | + | Larger than 20 MiB | `552` | The whole message, attachments included after base64 encoding. See [SMTP limits](/smtp). | + + The authentication checks keep forged mail out of your application: a message that passes was sent by a server the `From` domain authorizes. A sender whose domain has no SPF, no DKIM and no DMARC is refused; they need at least SPF or DKIM, which Gmail and Microsoft require of them anyway. + + A rejected message is not stored and does not appear in your message log; the sender's bounce is the only record. + + **Automatic Route Disabling:** - AhaSend disables routes after more than 100 consecutive failed attempts From ec5a0991efd0176f9a1d7dfaaddcb10e5886965d Mon Sep 17 00:00:00 2001 From: Mark Kraakman Date: Wed, 21 Oct 2026 15:49:20 +0200 Subject: [PATCH 3/3] Docs: rename rejection accordion --- integrations/routing.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/routing.mdx b/integrations/routing.mdx index 59206e3..97dd44d 100644 --- a/integrations/routing.mdx +++ b/integrations/routing.mdx @@ -756,7 +756,7 @@ The workflow functions below use application-owned callbacks such as `createSupp ``` - + AhaSend checks every message that arrives at `mx.ahasend.com` before it is queued for your route. A message that fails a check is refused during the SMTP transaction with a permanent error, so the sender's server returns it as a bounce and nothing reaches your endpoint. The bounce text quotes our reply: | Check | SMTP reply | What it means |