feat(email): Add attachments support (#186)
This commit is contained in:
@@ -14,6 +14,9 @@ keywords = ["email", "mailer"]
|
||||
[badges]
|
||||
travis-ci = { repository = "lettre/lettre_email" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "*"
|
||||
|
||||
[dependencies]
|
||||
email = "^0.0"
|
||||
mime = "^0.3"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
extern crate lettre;
|
||||
extern crate lettre_email;
|
||||
extern crate mime;
|
||||
|
||||
use lettre::{EmailTransport, SmtpTransport};
|
||||
use lettre_email::EmailBuilder;
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
let email = EmailBuilder::new()
|
||||
@@ -12,6 +14,7 @@ fn main() {
|
||||
.from("user@example.com")
|
||||
.subject("Hi, Hello world")
|
||||
.text("Hello world.")
|
||||
.attachment(Path::new("Cargo.toml"), None, mime::TEXT_PLAIN).unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -2,16 +2,20 @@
|
||||
|
||||
use self::Error::*;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// An enum of all error kinds.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Missinf sender
|
||||
/// Missing sender
|
||||
MissingFrom,
|
||||
/// Missing recipient
|
||||
MissingTo,
|
||||
/// Unparseable filename for attachment
|
||||
CannotParseFilename,
|
||||
/// IO error
|
||||
Io(io::Error),
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
@@ -25,6 +29,15 @@ impl StdError for Error {
|
||||
match *self {
|
||||
MissingFrom => "the sender is missing",
|
||||
MissingTo => "the recipient is missing",
|
||||
CannotParseFilename => "the attachment filename could not be parsed",
|
||||
Io(ref err) => err.description(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Error {
|
||||
Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,9 @@ use lettre::{EmailAddress, SendableEmail};
|
||||
use mime::Mime;
|
||||
use time::{Tm, now};
|
||||
use uuid::Uuid;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::io::Read;
|
||||
|
||||
/// Converts an address or an address with an alias to a `Header`
|
||||
pub trait IntoHeader {
|
||||
@@ -179,7 +182,7 @@ pub struct SimpleEmail {
|
||||
date: Option<Tm>,
|
||||
html: Option<String>,
|
||||
text: Option<String>,
|
||||
// attachments: Vec<String>,
|
||||
attachments: Vec<String>,
|
||||
headers: Vec<Header>,
|
||||
}
|
||||
|
||||
@@ -272,6 +275,17 @@ impl SimpleEmail {
|
||||
self.date = Some(date);
|
||||
}
|
||||
|
||||
/// Adds an attachment to the message
|
||||
pub fn attachment<S: Into<String>>(mut self, path: S) -> SimpleEmail {
|
||||
self.add_attachment(path);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an attachment to the message
|
||||
pub fn add_attachment<S: Into<String>>(&mut self, path: S) {
|
||||
self.attachments.push(path.into());
|
||||
}
|
||||
|
||||
/// Sets the email body to plain text content
|
||||
pub fn text<S: Into<String>>(mut self, body: S) -> SimpleEmail {
|
||||
self.set_text(body);
|
||||
@@ -585,6 +599,55 @@ impl EmailBuilder {
|
||||
self.date_issued = true;
|
||||
}
|
||||
|
||||
/// Adds an attachment to the email
|
||||
pub fn attachment(mut self, path: &Path, filename: Option<&str>, content_type: Mime) -> Result<EmailBuilder, Error> {
|
||||
self.set_attachment(path, filename, content_type)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Adds an attachment to the email
|
||||
/// If filename is not provided, the name of the file will be used.
|
||||
pub fn set_attachment(&mut self, path: &Path, filename: Option<&str>, content_type: Mime) -> Result<(), Error> {
|
||||
let file = File::open(path);
|
||||
let body = match file {
|
||||
Ok(mut f) => {
|
||||
let mut data = String::new();
|
||||
let read = f.read_to_string(&mut data);
|
||||
match read {
|
||||
Ok(_) => data,
|
||||
Err(e) => {
|
||||
return Err(From::from(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(From::from(e));
|
||||
}
|
||||
};
|
||||
|
||||
let actual_filename = match filename {
|
||||
Some(name) => name,
|
||||
None => match path.file_name() {
|
||||
Some(name) => match name.to_str() {
|
||||
Some(name) => name,
|
||||
None => return Err(Error::CannotParseFilename),
|
||||
},
|
||||
None => return Err(Error::CannotParseFilename),
|
||||
},
|
||||
};
|
||||
|
||||
let content = PartBuilder::new()
|
||||
.body(body)
|
||||
.header(("Content-Disposition", format!("attachment; filename=\"{}\"", actual_filename)))
|
||||
.header(("Content-Type", content_type.to_string()))
|
||||
.build();
|
||||
|
||||
self.set_message_type(MimeMultipartType::Mixed);
|
||||
self.add_child(content);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the message type
|
||||
pub fn message_type(mut self, message_type: MimeMultipartType) -> EmailBuilder {
|
||||
self.set_message_type(message_type);
|
||||
|
||||
Reference in New Issue
Block a user