Repository: lettre/lettre (language: rust)

Issue:
Construct mail from raw RFC822 with custom Envelope
Hey guys,
I am using lettre to write a fetchmail alternative.

For that, I need an API that allows me to build a message from the raw RFC822 with a custom envelope.
This worked flawlessly until (inclusively) a440ae5c79a18242a376deb0c28426ef092e32ab.
You can find the code I used for that [here](https://github.com/seijikun/idlemail/blob/master/src/destinations/smtp.rs#L91).

As far as I could see, the new Message API (introduced with 53aa5b4df622971fb5136f382575d3d552a7f8f6), however, does not seem to have such an option.

Am I missing something, or is there a better way to do this?
Otherwise: Could that API please be reintroduced in some way, or the other?

Thank you very much for lettre, it's been a pleasure to use!


Discussion / hints:
This API is still not as complete as the previous one, but should be before 0.10 is released.

Thanks for reporting, it is indeed an important use case.

Fix patch:
diff --git a/src/lib.rs b/src/lib.rs
index c118cef7b..f04b60b3e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -118,17 +118,16 @@ pub trait Transport<'a, B> {
 
     /// Sends the email
     /// FIXME not mut
-    fn send(&mut self, email: Message<B>) -> Self::Result
+
+    // email = message (bytes) + envelope
+    fn send(&mut self, message: Message<B>) -> Self::Result
     where
-        B: Display;
-    /*
+        B: Display,
     {
-        &mut self,
-        Box::new(Cursor::new(email.to_string().as_bytes())),
-            email.envelope(),
-            Uuid::new_v4().to_string(),
+        self.send_raw(message.envelope(), message.to_string().as_bytes())
+    }
 
-    }*/
+    fn send_raw(&mut self, envelope: &Envelope, email: &[u8]) -> Self::Result;
 
     // TODO allow sending generic data
 }
diff --git a/src/transport/file/mod.rs b/src/transport/file/mod.rs
index 21c7e81ce..af19d2a64 100644
--- a/src/transport/file/mod.rs
+++ b/src/transport/file/mod.rs
@@ -3,9 +3,8 @@
 //! It can be useful for testing purposes, or if you want to keep track of sent messages.
 //!
 
-use crate::{transport::file::error::FileResult, Envelope, Message, Transport};
+use crate::{transport::file::error::FileResult, Envelope, Transport};
 use std::{
-    fmt::Display,
     fs::File,
     io::prelude::*,
     path::{Path, PathBuf},
@@ -40,18 +39,15 @@ struct SerializableEmail {
 impl<'a, B> Transport<'a, B> for FileTransport {
     type Result = FileResult;
 
-    fn send(&mut self, email: Message<B>) -> Self::Result
-    where
-        B: Display,
-    {
+    fn send_raw(&mut self, envelope: &Envelope, email: &[u8]) -> Self::Result {
         let email_id = Uuid::new_v4();
 
         let mut file = self.path.clone();
         file.push(format!("{}.json", email_id));
 
         let serialized = serde_json::to_string(&SerializableEmail {
-            envelope: email.envelope().clone(),
-            message: email.to_string().into_bytes(),
+            envelope: envelope.clone(),
+            message: email.to_vec(),
         })?;
 
         File::create(file.as_path())?.write_all(serialized.as_bytes())?;
diff --git a/src/transport/sendmail/mod.rs b/src/transport/sendmail/mod.rs
index 2bb81d773..7a30b2c90 100644
--- a/src/transport/sendmail/mod.rs
+++ b/src/transport/sendmail/mod.rs
@@ -1,11 +1,11 @@
 //! The sendmail transport sends the email using the local sendmail command.
 //!
 
-use crate::{transport::sendmail::error::SendmailResult, Message, Transport};
+use crate::Envelope;
+use crate::{transport::sendmail::error::SendmailResult, Transport};
 use log::info;
 use std::{
     convert::AsRef,
-    fmt::Display,
     io::prelude::*,
     process::{Command, Stdio},
 };
@@ -39,33 +39,20 @@ impl SendmailTransport {
 impl<'a, B> Transport<'a, B> for SendmailTransport {
     type Result = SendmailResult;
 
-    fn send(&mut self, email: Message<B>) -> Self::Result
-    where
-        B: Display,
-    {
+    fn send_raw(&mut self, envelope: &Envelope, email: &[u8]) -> Self::Result {
         let email_id = Uuid::new_v4();
 
         // Spawn the sendmail command
         let mut process = Command::new(&self.command)
             .arg("-i")
             .arg("-f")
-            .arg(
-                email
-                    .envelope()
-                    .from()
-                    .map(|f| f.as_ref())
-                    .unwrap_or("\"\""),
-            )
-            .args(email.envelope().to())
+            .arg(envelope.from().map(|f| f.as_ref()).unwrap_or("\"\""))
+            .args(envelope.to())
             .stdin(Stdio::piped())
             .stdout(Stdio::piped())
             .spawn()?;
 
-        process
-            .stdin
-            .as_mut()
-            .unwrap()
-            .write_all(email.to_string().as_bytes())?;
+        process.stdin.as_mut().unwrap().write_all(email)?;
 
         info!("Wrote {} message to stdin", email_id);
 
diff --git a/src/transport/smtp/mod.rs b/src/transport/smtp/mod.rs
index 477d31cc3..089ef585b 100644
--- a/src/transport/smtp/mod.rs
+++ b/src/transport/smtp/mod.rs
@@ -13,6 +13,7 @@
 //! * SMTPUTF8 ([RFC 6531](http://tools.ietf.org/html/rfc6531))
 //!
 
+use crate::Envelope;
 use crate::{
     transport::smtp::{
         authentication::{
@@ -23,7 +24,7 @@ use crate::{
         error::{Error, SmtpResult},
         extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo},
     },
-    Message, Transport,
+    Transport,
 };
 use log::{debug, info};
 #[cfg(feature = "native-tls")]
@@ -31,7 +32,6 @@ use native_tls::{Protocol, TlsConnector};
 #[cfg(feature = "rustls")]
 use rustls::ClientConfig;
 use std::{
-    fmt::Display,
     net::{SocketAddr, ToSocketAddrs},
     time::Duration,
 };
@@ -445,12 +445,9 @@ impl<'a, B> Transport<'a, B> for SmtpTransport {
         feature = "cargo-clippy",
         allow(clippy::match_same_arms, clippy::cyclomatic_complexity)
     )]
-    fn send(&mut self, email: Message<B>) -> Self::Result
-    where
-        B: Display,
-    {
+    fn send_raw(&mut self, envelope: &Envelope, email: &[u8]) -> Self::Result {
         let email_id = Uuid::new_v4();
-        let envelope = email.envelope();
+        let envelope = envelope;
 
         if !self.client.is_connected() {
             self.connect()?;
@@ -509,7 +506,7 @@ impl<'a, B> Transport<'a, B> for SmtpTransport {
         try_smtp!(self.client.command(DataCommand), self);
 
         // Message content
-        let result = self.client.message(email.to_string().as_bytes());
+        let result = self.client.message(email);
 
         if let Ok(ref result) = result {
             // Increment the connection reuse counter
diff --git a/src/transport/stub/mod.rs b/src/transport/stub/mod.rs
index cacd72380..dcdf6dc4d 100644
--- a/src/transport/stub/mod.rs
+++ b/src/transport/stub/mod.rs
@@ -2,7 +2,8 @@
 //! testing purposes.
 //!
 
-use crate::{Message, Transport};
+use crate::Envelope;
+use crate::Transport;
 use log::info;
 use std::fmt::Display;
 
@@ -33,17 +34,14 @@ where
 {
     type Result = StubResult;
 
-    fn send(&mut self, email: Message<B>) -> Self::Result
-    where
-        B: Display,
-    {
+    fn send_raw(&mut self, envelope: &Envelope, _email: &[u8]) -> Self::Result {
         info!(
             "from=<{}> to=<{:?}>",
-            match email.envelope().from() {
+            match envelope.from() {
                 Some(address) => address.to_string(),
                 None => "".to_string(),
             },
-            email.envelope().to()
+            envelope.to()
         );
         self.response
     }


Test patch: