Skip to content

Conversation

@martoche
Copy link

@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
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
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
Owner

Can you use implicit TLS instead of STARTTLS?

@sapmli
Copy link

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

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.

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.

4 participants