Skip to content

client: export the InitStartTLS function#297

Open
martoche wants to merge 1 commit intoemersion:masterfrom
martoche:master
Open

client: export the InitStartTLS function#297
martoche wants to merge 1 commit intoemersion:masterfrom
martoche:master

Conversation

@martoche
Copy link
Copy Markdown

@martoche martoche commented Oct 8, 2025

If the initStartTLS function remains unexported, there is no way to get hold of a *Client after NewClient is called, and before initStartTLS is called.

This is needed if the Hello() method needs to be called manually to set a custom host name instead of the default "localhost".

In my specific case, the smtp-relay.gmail.com server rejects my request if I don't send a host name different of "localhost" in the EHLO command.

If the initStartTLS function remains unexported, there is no way to get
hold of a *Client after NewClient is called, and before initStartTLS is
called.

This is needed if the Hello() method needs to be called manually to set
a custom host name instead of the default "localhost".

In my specific case, the smtp-relay.gmail.com server rejects my request
if I don't send a host name different of "localhost" in the EHLO command.
@emersion
Copy link
Copy Markdown
Owner

emersion commented Oct 9, 2025

This is intentional: the HELLO hostname can be inspected and mutated by any intermediary along the way. The RFC says that the server must discard the HELLO hostname after STARTTLS.

The API has been designed this way (ie, without a Client method for STARTTLS) exactly to avoid this kind of security issue.

@martoche
Copy link
Copy Markdown
Author

I understand.

Unfortunately in my case, unless I'm missing something, smtp-relay.gmail.com on port 25 closes the connection if it receives EHLO localhost instead of the real hostname.

See nextcloud/server#29011 for example.

@emersion
Copy link
Copy Markdown
Owner

Can you use implicit TLS instead of STARTTLS?

@sapmli
Copy link
Copy Markdown

sapmli commented Oct 29, 2025

I suffer the same issue for an outgoing relay that's offering STARTTLS only if the EHLO matches an allowed client name.

Why not offer to set the localName in func NewClient(conn net.Conn, localName string) *Client ?

@ml1nk
Copy link
Copy Markdown

ml1nk commented Nov 10, 2025

You could try uponusolutions/go-smtp if you want to test if it works with a localName. The client has moved to /client and there is an option WithLocalName to set it (see benchmark_test.go for usage). The project scope differs and there will probably be more changes to the api, so it is clearly unstable if you compare it to upstream and will never be as rfc conform. I hope to get at least some changes merged back (@emersion if you are interested), when it is well tested.

@Hsn723
Copy link
Copy Markdown

Hsn723 commented Feb 26, 2026

This is intentional: the HELLO hostname can be inspected and mutated by any intermediary along the way. The RFC says that the server must discard the HELLO hostname after STARTTLS.

The API has been designed this way (ie, without a Client method for STARTTLS) exactly to avoid this kind of security issue.

In real world scenarios, a lot of mail servers expect the EHLO hostname to match A/PTR record, especially for communications coming from a MTA and regardless of whether the EHLO was received before or after STARTTLS. As per RFC, the server must indeed discard the EHLO hostname after STARTTLS, but the RFC does not restrict servers from performing EHLO validations before STARTTLS.

In fact, we've seen tarpitting behavior from a specific mail server (which I cannot disclose) where SMTP connections from EHLO localhost or similar untrustworthy hostnames are intentionally delayed for several seconds before being accepted, and this occurs before STARTTLS negotiation.

Concretely, the tarpitting behavior occurs during the initial EHLO and STARTTLS commands, so the delay due to tarpitting happens twice per SMTP session. Furthermore, if email volumes are substantially high, there is a real risk of the sending IP address ending on blacklists due to percieved poor practice around EHLO hostnames.

I therefore believe there is a real need to be able to set the localName for the client before the initial EHLO and fail to see how the current API design would mitigate any perceived security issue around EHLO hostname mutability.

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.

5 participants