feat(transport): Allow sending raw emails (fixes #409)

This commit is contained in:
Alexis Mousset
2020-04-25 11:16:56 +02:00
parent 8f31fb9804
commit 8b1399261f
5 changed files with 29 additions and 52 deletions

View File

@@ -118,17 +118,16 @@ pub trait Transport<'a, B> {
/// Sends the email /// Sends the email
/// FIXME not mut /// FIXME not mut
fn send(&mut self, email: Message<B>) -> Self::Result
where
B: Display;
/*
{
&mut self,
Box::new(Cursor::new(email.to_string().as_bytes())),
email.envelope(),
Uuid::new_v4().to_string(),
}*/ // email = message (bytes) + envelope
fn send(&mut self, message: Message<B>) -> Self::Result
where
B: Display,
{
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 // TODO allow sending generic data
} }

View File

@@ -3,9 +3,8 @@
//! It can be useful for testing purposes, or if you want to keep track of sent messages. //! 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::{ use std::{
fmt::Display,
fs::File, fs::File,
io::prelude::*, io::prelude::*,
path::{Path, PathBuf}, path::{Path, PathBuf},
@@ -40,18 +39,15 @@ struct SerializableEmail {
impl<'a, B> Transport<'a, B> for FileTransport { impl<'a, B> Transport<'a, B> for FileTransport {
type Result = FileResult; type Result = FileResult;
fn send(&mut self, email: Message<B>) -> Self::Result fn send_raw(&mut self, envelope: &Envelope, email: &[u8]) -> Self::Result {
where
B: Display,
{
let email_id = Uuid::new_v4(); let email_id = Uuid::new_v4();
let mut file = self.path.clone(); let mut file = self.path.clone();
file.push(format!("{}.json", email_id)); file.push(format!("{}.json", email_id));
let serialized = serde_json::to_string(&SerializableEmail { let serialized = serde_json::to_string(&SerializableEmail {
envelope: email.envelope().clone(), envelope: envelope.clone(),
message: email.to_string().into_bytes(), message: email.to_vec(),
})?; })?;
File::create(file.as_path())?.write_all(serialized.as_bytes())?; File::create(file.as_path())?.write_all(serialized.as_bytes())?;

View File

@@ -1,11 +1,11 @@
//! The sendmail transport sends the email using the local sendmail command. //! 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 log::info;
use std::{ use std::{
convert::AsRef, convert::AsRef,
fmt::Display,
io::prelude::*, io::prelude::*,
process::{Command, Stdio}, process::{Command, Stdio},
}; };
@@ -39,33 +39,20 @@ impl SendmailTransport {
impl<'a, B> Transport<'a, B> for SendmailTransport { impl<'a, B> Transport<'a, B> for SendmailTransport {
type Result = SendmailResult; type Result = SendmailResult;
fn send(&mut self, email: Message<B>) -> Self::Result fn send_raw(&mut self, envelope: &Envelope, email: &[u8]) -> Self::Result {
where
B: Display,
{
let email_id = Uuid::new_v4(); let email_id = Uuid::new_v4();
// Spawn the sendmail command // Spawn the sendmail command
let mut process = Command::new(&self.command) let mut process = Command::new(&self.command)
.arg("-i") .arg("-i")
.arg("-f") .arg("-f")
.arg( .arg(envelope.from().map(|f| f.as_ref()).unwrap_or("\"\""))
email .args(envelope.to())
.envelope()
.from()
.map(|f| f.as_ref())
.unwrap_or("\"\""),
)
.args(email.envelope().to())
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn()?; .spawn()?;
process process.stdin.as_mut().unwrap().write_all(email)?;
.stdin
.as_mut()
.unwrap()
.write_all(email.to_string().as_bytes())?;
info!("Wrote {} message to stdin", email_id); info!("Wrote {} message to stdin", email_id);

View File

@@ -13,6 +13,7 @@
//! * SMTPUTF8 ([RFC 6531](http://tools.ietf.org/html/rfc6531)) //! * SMTPUTF8 ([RFC 6531](http://tools.ietf.org/html/rfc6531))
//! //!
use crate::Envelope;
use crate::{ use crate::{
transport::smtp::{ transport::smtp::{
authentication::{ authentication::{
@@ -23,7 +24,7 @@ use crate::{
error::{Error, SmtpResult}, error::{Error, SmtpResult},
extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo}, extension::{ClientId, Extension, MailBodyParameter, MailParameter, ServerInfo},
}, },
Message, Transport, Transport,
}; };
use log::{debug, info}; use log::{debug, info};
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
@@ -31,7 +32,6 @@ use native_tls::{Protocol, TlsConnector};
#[cfg(feature = "rustls")] #[cfg(feature = "rustls")]
use rustls::ClientConfig; use rustls::ClientConfig;
use std::{ use std::{
fmt::Display,
net::{SocketAddr, ToSocketAddrs}, net::{SocketAddr, ToSocketAddrs},
time::Duration, time::Duration,
}; };
@@ -445,12 +445,9 @@ impl<'a, B> Transport<'a, B> for SmtpTransport {
feature = "cargo-clippy", feature = "cargo-clippy",
allow(clippy::match_same_arms, clippy::cyclomatic_complexity) allow(clippy::match_same_arms, clippy::cyclomatic_complexity)
)] )]
fn send(&mut self, email: Message<B>) -> Self::Result fn send_raw(&mut self, envelope: &Envelope, email: &[u8]) -> Self::Result {
where
B: Display,
{
let email_id = Uuid::new_v4(); let email_id = Uuid::new_v4();
let envelope = email.envelope(); let envelope = envelope;
if !self.client.is_connected() { if !self.client.is_connected() {
self.connect()?; self.connect()?;
@@ -509,7 +506,7 @@ impl<'a, B> Transport<'a, B> for SmtpTransport {
try_smtp!(self.client.command(DataCommand), self); try_smtp!(self.client.command(DataCommand), self);
// Message content // Message content
let result = self.client.message(email.to_string().as_bytes()); let result = self.client.message(email);
if let Ok(ref result) = result { if let Ok(ref result) = result {
// Increment the connection reuse counter // Increment the connection reuse counter

View File

@@ -2,7 +2,8 @@
//! testing purposes. //! testing purposes.
//! //!
use crate::{Message, Transport}; use crate::Envelope;
use crate::Transport;
use log::info; use log::info;
use std::fmt::Display; use std::fmt::Display;
@@ -33,17 +34,14 @@ where
{ {
type Result = StubResult; type Result = StubResult;
fn send(&mut self, email: Message<B>) -> Self::Result fn send_raw(&mut self, envelope: &Envelope, _email: &[u8]) -> Self::Result {
where
B: Display,
{
info!( info!(
"from=<{}> to=<{:?}>", "from=<{}> to=<{:?}>",
match email.envelope().from() { match envelope.from() {
Some(address) => address.to_string(), Some(address) => address.to_string(),
None => "".to_string(), None => "".to_string(),
}, },
email.envelope().to() envelope.to()
); );
self.response self.response
} }