Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support email.tlsname with old Twisted versions
Old twisted versions' ESMTPSenderFactory doesn't support the `hostname` parameter used to implement the email.tlsname configuration option (and also the email.enable_tls option). This backports that parameter by extending ESMTPSenderFactory when twisted is old. Were shadowing the attribute `ESMTPSenderFactory.protocol` with the method `_BackportESMTPSenderFactory.protocol` here, that is on purpose. That attribute usually contains the `ESMTPSender` class. It is used by `ESMTPSenderFactory.buildProtocol` as a Callable to instantiate an `ESMTPSender`. By providing this Callable as a method, the previously set `_BackportESMTPSenderFactory.__hostname` can be provided to the newly instantiated `_BackportESMTPSender`. Note the `# type: ignore` annotation required to pass the mypy type checker. Mypy assigns the type `Type[ESMTPSender]` to `ESMTPSenderFactory.protocol`, which is valid (twisted does assign a `Type[ESMTPSender]`), but AFAICT it is only ever used to instantiate values of that type, i.e. as a `Callable[[...], ESMTPSender]`, so overriding it with a method with that signature should be fine. It is a public attribute though, so technically it could be accessed somewhere else, actually requiring a `Type[ESMTPSender]`. But we do need to get the `hostname` parameter to our `_BackportESMTPSender` somehow, and this seems neater compared to the two alternatives I considered: * Override `ESMTPSenderFactory.buildProtocol` instead of `ESMTPSenderFactory.protocol`. That would require copying the entire body of `ESMTPSenderFactory.buildProtocol` into `_BackportESMTPSenderFactory.buildProtocol`, most of which isn't related to the change we're trying to implement. That just seems unnecessarily brittle (e.g. maybe different old twisted versions could have different versions `buildProtocol` (I didn't check), picking one of them could lead to an inconsistent object). * Set `self.protocol` in `_BackportESMTPSenderFactory.__init__` to a class defined within `_BackportESMTPSenderFactory.__init__`, such that it can close over the `hostname` parameter---i.e. each instantiation of the `_BackportESMTPSenderFactory` would define a new class extending `ESMTPSender` specific to that instantiation's `hostname` parameter. That's a nice (functional-style) solution, but I think the solution implemented here might feel more natural to the average python programmer. This effectively retrofits modern twisted's [1] `hostname` parameter to old twisted's [2] classes. [1]: https://github.com/twisted/twisted/blob/twisted-24.11.0/src/twisted/mail/smtp.py#L1992 [2]: https://github.com/twisted/twisted/blob/twisted-21.2.0/src/twisted/mail/smtp.py#L2005
- Loading branch information