1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
use reqwest; use std::collections::HashMap; use serde::{Deserialize}; use reqwest::Error as ReqError; const MAILGUN_API: &str = "https://api.mailgun.net/v3"; const MESSAGES_ENDPOINT: &str = "messages"; #[derive(Default)] pub struct Mailgun { pub api_key: String, pub domain: String, pub message: Message, } pub type SendResult<T> = Result<T, ReqError>; #[derive(Deserialize, Debug, PartialEq)] pub struct SendResponse { pub message: String, pub id: String, } impl Mailgun{ pub fn send(self, sender: &EmailAddress) -> SendResult<SendResponse> { let client = reqwest::Client::new(); let mut params = self.message.to_params(); params.insert("from".to_string(), sender.to_string()); let url = format!("{}/{}/{}", MAILGUN_API, self.domain, MESSAGES_ENDPOINT); let mut res = client.post(&url) .basic_auth("api", Some(self.api_key.clone())) .form(¶ms) .send()? .error_for_status()?; let parsed: SendResponse = res.json()?; Ok(parsed) } } #[derive(Default)] pub struct Message { pub to: Vec<EmailAddress>, pub cc: Vec<EmailAddress>, pub bcc: Vec<EmailAddress>, pub subject: String, pub text: String, pub html: String, } impl Message { fn to_params(self) -> HashMap<String, String> { let mut params = HashMap::new(); Message::add_recipients("to", self.to, &mut params); Message::add_recipients("cc", self.cc, &mut params); Message::add_recipients("bcc", self.bcc, &mut params); params.insert(String::from("subject"), self.subject); params.insert(String::from("text"), self.text); params.insert(String::from("html"), self.html); params } fn add_recipients(field: &str, addresses: Vec<EmailAddress>, params: &mut HashMap<String, String>) { if !addresses.is_empty() { let joined = addresses.iter() .map(EmailAddress::to_string) .collect::<Vec<String>>() .join(","); params.insert(field.to_owned(), joined); } } } pub struct EmailAddress { name: Option<String>, address: String, } impl EmailAddress { pub fn address(address: &str) -> Self { EmailAddress { name: None, address: address.to_string() } } pub fn name_address(name: &str, address: &str ) -> Self { EmailAddress { name: Some(name.to_string()), address: address.to_string() } } pub fn email(&self) -> &str { &self.address } pub fn to_string(&self) -> String { match self.name { Some(ref name) => format!("{} <{}>", name, self.address), None => self.address.clone() } } }