use lettre::{
message::{Message},
transport::smtp::authentication::Credentials,
Transport,
};
use lettre::SmtpTransport;
use std::env;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum EmailSenderError {
#[error("Environment variable not found: {0}")]
EnvVarNotFound(String),
#[error("Failed to parse SMTP port: {0}")]
ParsePortError(#[from] std::num::ParseIntError),
#[error("Failed to parse mailbox: {0}")]
ParseMailboxError(#[from] lettre::address::AddressError),
#[error("SMTP transport error: {0}")]
SmtpTransportError(#[from] lettre::transport::smtp::Error),
#[error("Message building error: {0}")]
MessageBuildError(#[from] lettre::error::Error),
}
pub struct EmailOptions {
pub smtp_server: String,
pub smtp_port: u16,
pub smtp_username: String,
pub smtp_password: String,
pub from: String,
pub to: String,
pub subject: String,
pub body: String,
}
impl EmailOptions {
pub fn from_env() -> Result<Self, EmailSenderError> {
dotenv::dotenv().ok();
Ok(Self {
smtp_server: env::var("SMTP_SERVER").map_err(|_| EmailSenderError::EnvVarNotFound("SMTP_SERVER".to_string()))?,
smtp_port: env::var("SMTP_PORT")
.map_err(|_| EmailSenderError::EnvVarNotFound("SMTP_PORT".to_string()))?
.parse()?,
smtp_username: env::var("SMTP_USERNAME").map_err(|_| EmailSenderError::EnvVarNotFound("SMTP_USERNAME".to_string()))?,
smtp_password: env::var("SMTP_PASSWORD").map_err(|_| EmailSenderError::EnvVarNotFound("SMTP_PASSWORD".to_string()))?,
from: env::var("EMAIL_FROM").map_err(|_| EmailSenderError::EnvVarNotFound("EMAIL_FROM".to_string()))?,
to: env::var("EMAIL_TO").map_err(|_| EmailSenderError::EnvVarNotFound("EMAIL_TO".to_string()))?,
subject: "Default Subject".to_string(),
body: "Default body".to_string(),
})
}
pub fn new(
smtp_server: String,
smtp_port: u16,
smtp_username: String,
smtp_password: String,
from: String,
to: String,
subject: String,
body: String,
) -> Self {
Self {
smtp_server,
smtp_port,
smtp_username,
smtp_password,
from,
to,
subject,
body,
}
}
}
pub fn send_email(options: EmailOptions) -> Result<(), EmailSenderError> {
let email = Message::builder()
.from(options.from.parse()?)
.to(options.to.parse()?)
.subject(&options.subject)
.body(options.body)
.map_err(EmailSenderError::MessageBuildError)?;
let creds = Credentials::new(options.smtp_username, options.smtp_password);
let mailer = SmtpTransport::relay(&options.smtp_server)?
.port(options.smtp_port)
.credentials(creds)
.build();
mailer.send(&email)?;
println!("Email sent successfully!");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_send_email() {
let options = EmailOptions::new(
"smtp.example.com".to_string(),
587,
"your_username".to_string(),
"your_password".to_string(),
"from@example.com".to_string(),
"to@example.com".to_string(),
"Test Subject".to_string(),
"Test Body".to_string(),
);
assert!(true);
}
}