mail-send icon indicating copy to clipboard operation
mail-send copied to clipboard

Integration with mail-parser

Open mripard opened this issue 3 years ago • 2 comments

Hi, it's me again

What I'm trying to build requires to store mails on disk, before reading them back and sending them.

Storing them on disk using mail-parser is easy thanks to serde. An alternative could be to store them raw which is trivial too.

However, sending them through mail-send seems to be a bit of a pain point. Indeed, the IntoMessage trait that Transport.send expects is implemented for mail-parser's Message and mail-builder MessageBuilder.

However, neither mail-parser::Message nor mail-builder::MessageBuilder support building the structure from the raw text or through Deserialize.

I guess implementing IntoMessage for mail-parser::Message could work, but it feels like both mail-parser::Message and mail-send::smtp::message::Message could be the same structure, that would implement Serialize/Deserialize?

Thanks!

mripard avatar Jun 03 '22 14:06 mripard

Hi,

Do you need to send the email exactly as it was? If that is the case, you could send it in raw format as in this example:

https://github.com/stalwartlabs/mail-send/blob/main/examples/smtp_raw_message.rs

mdecimus avatar Jun 03 '22 16:06 mdecimus

It works indeed, but we would still need to parse the raw message using MessageParser in order to retrieve the to and from fields.

We end up with something like this

use mail_builder::MessageBuilder;
use mail_parser::Message as MessageParser;
use mail_send::{smtp::message::Message, Transport};

#[tokio::main]
async fn main() {
    let message = MessageBuilder::new()
        .from(("Test", "[email protected]"))
        .to("[email protected]")
        .subject("Test Email")
        .text_body("Hi Mark!");

    let bytes = message.write_to_vec()
        .unwrap();

    let msg = MessageParser::parse(&bytes)
        .unwrap();

    let from = match msg.get_from() {
        mail_parser::HeaderValue::Address(address) => address.address.as_ref().unwrap(),
        _ => todo!(),
    }.to_string();

    let to = match msg.get_to() {
        mail_parser::HeaderValue::Address(address) => address.address.as_ref().unwrap(),
        _ => todo!(),
    }.to_string();

    let msg_sent = Message::empty()
        .from(from)
        .to(to)
        .body(&bytes);

    Transport::new("smtp.example.org")
        .credentials("[email protected]", "passwd")
        .connect_tls()
        .await
        .unwrap()
        .send(msg_sent)
        .await
        .unwrap()
}

Which is still fairly tedious (and possibly incomplete)

mripard avatar Jun 08 '22 12:06 mripard

did you add something to 0.2.2 to make this any easier? I didn't find anything obvious to me

mripard avatar Aug 31 '22 07:08 mripard