Repository: lettre/lettre (language: rust)

Issue:
Change FileTransport to save into .eml format
Personally whenever I want to test lettre I send an email addressed to myself. Currently `FileTransport` saves emails in a custom json, which isn't that useful, but what if we instead saved it into an [.eml](https://openemlfile.com)?

This format is supported by email clients, making it very easy to test creating a message without having to actually send it.


Discussion / hints:
I'll give this a try. My understanding so far is that it's mainly about writing out the formatted message instead of the json structure. Are there other things i need to consider?
I haven't looked deep into it, from what I've seen there's to remove the old implementation and have the encoded message received by `send_raw` be saved into a file.

Fix patch:
diff --git a/src/transport/file/mod.rs b/src/transport/file/mod.rs
index 711641b15..7b6ce60f2 100644
--- a/src/transport/file/mod.rs
+++ b/src/transport/file/mod.rs
@@ -1,5 +1,5 @@
 //! The file transport writes the emails to the given directory. The name of the file will be
-//! `message_id.json`.
+//! `message_id.eml`.
 //! It can be useful for testing purposes, or if you want to keep track of sent messages.
 //!
 //! ## Sync example
@@ -85,17 +85,14 @@
 //!
 //! Example result
 //!
-//! ```json
-//! {
-//!   "envelope": {
-//!     "forward_path": [
-//!       "hei@domain.tld"
-//!     ],
-//!     "reverse_path": "nobody@domain.tld"
-//!   },
-//!   "raw_message": null,
-//!   "message": "From: NoBody <nobody@domain.tld>\r\nReply-To: Yuin <yuin@domain.tld>\r\nTo: Hei <hei@domain.tld>\r\nSubject: Happy new year\r\nDate: Tue, 18 Aug 2020 22:50:17 GMT\r\n\r\nBe happy!"
-//! }
+//! ```eml
+//! From: NoBody <nobody@domain.tld>
+//! Reply-To: Yuin <yuin@domain.tld>
+//! To: Hei <hei@domain.tld>
+//! Subject: Happy new year
+//! Date: Tue, 18 Aug 2020 22:50:17 GMT
+//!
+//! Be happy!
 //! ```
 
 pub use self::error::Error;
@@ -143,43 +140,17 @@ struct SerializableEmail<'a> {
     message: Option<&'a str>,
 }
 
-impl FileTransport {
-    fn send_raw_impl(
-        &self,
-        envelope: &Envelope,
-        email: &[u8],
-    ) -> Result<(Uuid, PathBuf, String), serde_json::Error> {
-        let email_id = Uuid::new_v4();
-        let file = self.path.join(format!("{}.json", email_id));
-
-        let serialized = match str::from_utf8(email) {
-            // Serialize as UTF-8 string if possible
-            Ok(m) => serde_json::to_string(&SerializableEmail {
-                envelope: envelope.clone(),
-                message: Some(m),
-                raw_message: None,
-            }),
-            Err(_) => serde_json::to_string(&SerializableEmail {
-                envelope: envelope.clone(),
-                message: None,
-                raw_message: Some(email),
-            }),
-        }?;
-
-        Ok((email_id, file, serialized))
-    }
-}
-
 impl Transport for FileTransport {
     type Ok = Id;
     type Error = Error;
 
-    fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
+    fn send_raw(&self, _envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
         use std::fs;
 
-        let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?;
+        let email_id = Uuid::new_v4();
+        let file = self.path.join(format!("{}.eml", email_id));
 
-        fs::write(file, serialized)?;
+        fs::write(file, email)?;
         Ok(email_id.to_string())
     }
 }
@@ -190,12 +161,13 @@ impl AsyncStd1Transport for FileTransport {
     type Ok = Id;
     type Error = Error;
 
-    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
+    async fn send_raw(&self, _envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
         use async_std::fs;
 
-        let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?;
+        let email_id = Uuid::new_v4();
+        let file = self.path.join(format!("{}.eml", email_id));
 
-        fs::write(file, serialized).await?;
+        fs::write(file, email).await?;
         Ok(email_id.to_string())
     }
 }
@@ -206,12 +178,13 @@ impl Tokio02Transport for FileTransport {
     type Ok = Id;
     type Error = Error;
 
-    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
+    async fn send_raw(&self, _envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
         use tokio02_crate::fs;
 
-        let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?;
+        let email_id = Uuid::new_v4();
+        let file = self.path.join(format!("{}.eml", email_id));
 
-        fs::write(file, serialized).await?;
+        fs::write(file, email).await?;
         Ok(email_id.to_string())
     }
 }
@@ -222,12 +195,13 @@ impl Tokio03Transport for FileTransport {
     type Ok = Id;
     type Error = Error;
 
-    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
+    async fn send_raw(&self, _envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
         use tokio03_crate::fs;
 
-        let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?;
+        let email_id = Uuid::new_v4();
+        let file = self.path.join(format!("{}.eml", email_id));
 
-        fs::write(file, serialized).await?;
+        fs::write(file, email).await?;
         Ok(email_id.to_string())
     }
 }


Test patch:
diff --git a/tests/transport_file.rs b/tests/transport_file.rs
index 8f33f9762..eccb352be 100644
--- a/tests/transport_file.rs
+++ b/tests/transport_file.rs
@@ -27,14 +27,14 @@ mod test {
         let result = sender.send(&email);
         let id = result.unwrap();
 
-        let file = temp_dir().join(format!("{}.json", id));
+        let file = temp_dir().join(format!("{}.eml", id));
         let mut f = File::open(file.clone()).unwrap();
         let mut buffer = String::new();
         let _ = f.read_to_string(&mut buffer);
 
         assert_eq!(
             buffer,
-            "{\"envelope\":{\"forward_path\":[\"hei@domain.tld\"],\"reverse_path\":\"nobody@domain.tld\"},\"raw_message\":null,\"message\":\"From: NoBody <nobody@domain.tld>\\r\\nReply-To: Yuin <yuin@domain.tld>\\r\\nTo: Hei <hei@domain.tld>\\r\\nSubject: Happy new year\\r\\nDate: Tue, 15 Nov 1994 08:12:31 GMT\\r\\n\\r\\nBe happy!\"}");
+            "From: NoBody <nobody@domain.tld>\r\nReply-To: Yuin <yuin@domain.tld>\r\nTo: Hei <hei@domain.tld>\r\nSubject: Happy new year\r\nDate: Tue, 15 Nov 1994 08:12:31 GMT\r\n\r\nBe happy!");
         remove_file(file).unwrap();
     }
 
@@ -56,14 +56,14 @@ mod test {
         let result = sender.send(email).await;
         let id = result.unwrap();
 
-        let file = temp_dir().join(format!("{}.json", id));
+        let file = temp_dir().join(format!("{}.eml", id));
         let mut f = File::open(file.clone()).unwrap();
         let mut buffer = String::new();
         let _ = f.read_to_string(&mut buffer);
 
         assert_eq!(
             buffer,
-            "{\"envelope\":{\"forward_path\":[\"hei@domain.tld\"],\"reverse_path\":\"nobody@domain.tld\"},\"raw_message\":null,\"message\":\"From: NoBody <nobody@domain.tld>\\r\\nReply-To: Yuin <yuin@domain.tld>\\r\\nTo: Hei <hei@domain.tld>\\r\\nSubject: Happy new year\\r\\nDate: Tue, 15 Nov 1994 08:12:31 GMT\\r\\n\\r\\nBe happy!\"}");
+            "From: NoBody <nobody@domain.tld>\r\nReply-To: Yuin <yuin@domain.tld>\r\nTo: Hei <hei@domain.tld>\r\nSubject: Happy new year\r\nDate: Tue, 15 Nov 1994 08:12:31 GMT\r\n\r\nBe happy!");
         remove_file(file).unwrap();
     }
 
@@ -85,14 +85,14 @@ mod test {
         let result = sender.send(email).await;
         let id = result.unwrap();
 
-        let file = temp_dir().join(format!("{}.json", id));
+        let file = temp_dir().join(format!("{}.eml", id));
         let mut f = File::open(file.clone()).unwrap();
         let mut buffer = String::new();
         let _ = f.read_to_string(&mut buffer);
 
         assert_eq!(
             buffer,
-            "{\"envelope\":{\"forward_path\":[\"hei@domain.tld\"],\"reverse_path\":\"nobody@domain.tld\"},\"raw_message\":null,\"message\":\"From: NoBody <nobody@domain.tld>\\r\\nReply-To: Yuin <yuin@domain.tld>\\r\\nTo: Hei <hei@domain.tld>\\r\\nSubject: Happy new year\\r\\nDate: Tue, 15 Nov 1994 08:12:31 GMT\\r\\n\\r\\nBe happy!\"}");
+            "From: NoBody <nobody@domain.tld>\r\nReply-To: Yuin <yuin@domain.tld>\r\nTo: Hei <hei@domain.tld>\r\nSubject: Happy new year\r\nDate: Tue, 15 Nov 1994 08:12:31 GMT\r\n\r\nBe happy!");
         remove_file(file).unwrap();
     }
 }