Please support PROXY header
Is your feature request related to a problem? Please describe.
aiosmtplib needs to support the haproxy PROXY protocol, to allow an aiosmtplib.SMTP client to spoof a connecting IP to any SMTP server which knows the connecting client, and is pre-configured to trust and permit this.
Reference: https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/client-ip-preservation/enable-proxy-protocol/
aiosmtpd supports PROXY. If enabled, an aiosmtpd-based server will wait after connection for the PROXY header before sending its 220 greeting.
Describe the solution you'd like
Ideally, the SMTP constructor needs to accept one or more keywords to configure it to send PROXY header after connecting.
In my production workflow, I've subclassed SMTP, and:
- Overridden the constructor to accept/validate/store a proxy parameter
- Overridden
_create_connection(), copied/pasted the 'official' method's code, and inserted a couple of lines to send a proxy header before theread_response()stage. Here's an excerpt:
# original code - after the connection succeeds
self.protocol = protocol
self.transport = transport
# my insertion
# send PROXY header if we have one
if self.proxyHdr is not None:
transport.write(self.proxyHdr)
pass
# back to original code
try:
response = await protocol.read_response(timeout=timeout)
... check exceptions etc etc
However, I'm nervous about continuing to use a copy/paste/patch of _create_connection() in my codebase, and would be much happier to upgrade my field to a version of aiosmtplib that has PROXY support officially baked in.
Note that in my current implementation, my constructor accepts a literal bytes parameter, comprising the exact PROXY header to send. This was just done in haste. But ideally, a constructor would instead accept a set of parameters from which the SMTP client would generate the PROXY header itself.
Describe alternatives you've considered I could shim the connect. Not pleasant. I could use other SMTP clients. Not pleasant either. Apart from the lack of PROXY support, aiosmtplib is best-of-breed in the asyncio SMTP client space.
Additional context I'm monitoring health of mail flow nodes, and need PROXY support in the SMTP client to be able to complete the health assessments.
Thanks, I wasn't familiar with the PROXY protocol, will take a look.
@cole PROXY is absolutely essential in situations where a node needs to act as a mail proxy, receiving submissions from upstream clients, then forwarding these downstream and preserving the upstream client's IP. Just one example of this is load-balancing setups.
Misuse of this by bad actors tends to be rare, happening only in cases where the trusting downstream server isn't enforcing an IP whitelist of who it allows to use for proxying.
Two approaches to PROXY implementation for an SMTP client:
- Once instantiated with PROXY enabled (via constructor params), then always send the proxy packet first before reading for a
220greeting, versus - Wait a period of time (constructor param, default maybe 1-3 seconds) for a greeting, and if it doesn't arrive, then send the proxy packet.
Option 2 is a bit controversial because network conditions could delay a greeting from a non-proxy-compatible server, and cause the client to mistakenly send the proxy packet, then suffer an adverse 5xx response, and then hang up.
For context, aiosmtpd listeners are constructed either in PROXY-only or non-PROXY mode, thus suffering no timing semantics.