Skip to content

Discard pooled SMTP connections on terminal SMTP errors#19

Closed
MaximilianKohler wants to merge 2 commits into
knadh:masterfrom
MaximilianKohler:patch-1
Closed

Discard pooled SMTP connections on terminal SMTP errors#19
MaximilianKohler wants to merge 2 commits into
knadh:masterfrom
MaximilianKohler:patch-1

Conversation

@MaximilianKohler

@MaximilianKohler MaximilianKohler commented Jan 9, 2026

Copy link
Copy Markdown

Some SMTP servers close a session after policy limits (e.g. time or message count) and return 421 Service not available, closing transmission channel, or close the connection mid-DATA.

In these cases the SMTP connection is no longer usable and must not be returned to the pool.

This change improves RFC-5321 compliance by treating 421 and connection-level errors as terminal, ensuring dead connections are discarded and retried on fresh connections.

This PR was created with ChatGPT and closes: #18

Some SMTP servers close a session after policy limits (e.g. time or message count) and return 421 Service not available, closing transmission channel, or close the connection mid-DATA.

In these cases the SMTP connection is no longer usable and must not be returned to the pool.

This change improves RFC-5321 compliance by treating 421 and connection-level errors as terminal, ensuring dead connections are discarded and retried on fresh connections.
GPT suggested this as well, but I didn't include it:

## 3️⃣ Retry-path behavior (acceptable, but tighten wording)

Your retry path is:

```go
retry, err := c.send(e)
...
_ = p.returnConn(c, err)
if !retry {
	return err
}
```

This is fine **because**:

* Terminal errors discard the connection
* Retries will borrow a new connection
* Retry count is bounded

However, maintainers may ask:

> “What if `send()` returns retryable=true AND terminal=true?”

Answer:
That’s correct behavior — retry the message, but on a new connection.

To pre-empt that question, add **one comment** in `Send()`:

```go
// returnConn will discard the connection on terminal errors even if the
// message itself is retryable.
```

This prevents review churn.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Solving 421 Maximum message count per session reached errors

1 participant