piknik icon indicating copy to clipboard operation
piknik copied to clipboard

feat: add lmtp support to smtp transport

Open CertainLach opened this issue 3 years ago • 5 comments

I'm not sure what this API should look like, but I have tried my best to reuse most of the code.

Maybe it would be better to store LMTP as a config parameter and return multiple responses for plain SMTP too, instead of specializing on LMTP protocol using const generic?

I have tried implementing separate struct for LMTP protocol, wrapping SMTP, however it would be too much boilerplate to delegate every method except send to wrapped SMTP connection.

I also have tried to use sealed generic instead of boolean const, but this didn't go well too (But maybe this approach can be implemented, if I'll try harder?)

trait Protocol;
struct Smtp;
struct Lmtp;
impl Protocol for Smtp {}
impl Protocol for Lmtp {}

impl<P: Protocol> MtpConnection<P> {...}
impl MtpConnection<Smtp> {...}
impl MtpConnection<Lmtp> {...}

Fixes: https://github.com/lettre/lettre/issues/820

CertainLach avatar Nov 13 '22 16:11 CertainLach

Thanks for the PR. I'll try looking at it in the following days.

paolobarbolini avatar Nov 16 '22 12:11 paolobarbolini

Any progress?

Tsai002 avatar Jun 15 '23 07:06 Tsai002

How does this handle failures for individual recipients (https://datatracker.ietf.org/doc/html/rfc2033#section-4.3)? I think it might need to return a Vec<Result<Response, Error>> with one entry for each recipient.

I would also prefer to have LMTP separated out rather than a boolean parameter to the SMTP code that says "not actually SMTP". Possibly refactor the common code as "MailTransferProtocols" and then implement (E)SMTP and LMTP on top of that.

Other than that I'd love to see LMTP in lettre.

daviessm avatar Jul 12 '23 14:07 daviessm

How does this handle failures for individual recipients (https://datatracker.ietf.org/doc/html/rfc2033#section-4.3)? I think it might need to return a Vec<Result<Response, Error>> with one entry for each recipient.

It does that using command_negative method, which skips conversion from negative response to Result, thus every response in the result vector might be negative, and that is exactly what we want.

Top-level error then only provides pool/server errors, such as connection failures, and usage of unsupported features in envelope, and I think this is the way it should work with the LMTP server (I have looked at the spec while implementing this feature, but I don't remember the exact motivation now).

I would also prefer to have LMTP separated out rather than a boolean parameter to the SMTP code that says "not actually SMTP". Possibly refactor the common code as "MailTransferProtocols" and then implement (E)SMTP and LMTP on top of that.

Yep, I don't like current approach (boolean generic) either, but I haven't managed to come with the better implementation, and I'm too lazy to implement it the other way.

I will finish this PR if we decide that current implementation is ok, or figure out an easier implementation with least amount of code duplication.

CertainLach avatar Jul 13 '23 07:07 CertainLach

How does this handle failures for individual recipients (https://datatracker.ietf.org/doc/html/rfc2033#section-4.3)? I think it might need to return a Vec<Result<Response, Error>> with one entry for each recipient.

It does that using command_negative method, which skips conversion from negative response to Result, thus every response in the result vector might be negative, and that is exactly what we want.

Oh yes I see it now, thanks. https://github.com/CertainLach/lettre/blob/5a68a43b9e449d27632cc9213552db5488c68a9c/src/transport/smtp/client/connection.rs#L410

daviessm avatar Jul 13 '23 09:07 daviessm