feat(transport): Allow sending raw emails (fixes #409)
This commit is contained in:
19
src/lib.rs
19
src/lib.rs
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())?;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user