Add mailer module

This commit is contained in:
Alexis Mousset
2014-12-10 14:02:20 +01:00
parent 9f99382b98
commit dd1ba7d8cf
3 changed files with 375 additions and 0 deletions

104
src/mailer/address.rs Normal file
View File

@@ -0,0 +1,104 @@
// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Simple SMTP "address" (very incomplete)
use std::fmt::{Show, Formatter, Result};
use common::SP;
/// Converts an adress or an address with an alias to an `Address`
pub trait ToAddress {
/// Converts to an `Address` struct
fn to_address(&self) -> Address;
}
impl ToAddress for Address {
fn to_address(&self) -> Address {
(*self).clone()
}
}
impl<'a> ToAddress for &'a str {
fn to_address(&self) -> Address {
Address::new(*self, None)
}
}
impl<'a> ToAddress for (&'a str, &'a str) {
fn to_address(&self) -> Address {
let (address, alias) = *self;
Address::new(address, Some(alias))
}
}
/// Contains an address with an optionnal alias
#[deriving(PartialEq,Eq,Clone)]
pub struct Address {
/// The address
address: String,
/// The alias
alias: Option<String>,
}
impl Show for Address {
fn fmt(&self, f: &mut Formatter) -> Result {
f.write(match self.alias {
Some(ref alias_string) => format!("{}{}<{}>", alias_string, SP, self.address.as_slice()),
None => self.address.clone(),
}.as_bytes())
}
}
impl Address {
/// Creates an address
pub fn new(address: &str, alias: Option<&str>) -> Address {
Address {
address: address.to_string(),
alias: match alias {
Some(ref alias_string) => Some(alias_string.to_string()),
None => None,
}
}
}
/// Return only the address
pub fn get_address(&self) -> String {
self.address.clone()
}
}
#[cfg(test)]
mod test {
use super::Address;
#[test]
fn test_new() {
assert_eq!(
Address::new("address", Some("alias")),
Address{address: "address".to_string(), alias: Some("alias".to_string())}
);
assert_eq!(
Address::new("address", None),
Address{address: "address".to_string(), alias: None}
);
}
#[test]
fn test_fmt() {
assert_eq!(
format!("{}", Address::new("address", None)),
"address".to_string()
);
assert_eq!(
format!("{}", Address::new("address", Some("alias"))),
"alias <address>".to_string()
);
}
}

76
src/mailer/header.rs Normal file
View File

@@ -0,0 +1,76 @@
// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Simple SMTP headers
use std::fmt::{Show, Formatter, Result};
use common::{SP, COLON};
/// Converts to an `Header`
pub trait ToHeader {
/// Converts to an `Header` struct
fn to_header(&self) -> Header;
}
impl ToHeader for Header {
fn to_header(&self) -> Header {
(*self).clone()
}
}
impl<'a> ToHeader for (&'a str, &'a str) {
fn to_header(&self) -> Header {
let (name, value) = *self;
Header::new(name, value)
}
}
/// Contains a header
#[deriving(PartialEq,Eq,Clone)]
pub struct Header {
/// Name of the header
name: String,
/// Value of the header
value: String,
}
impl Show for Header {
fn fmt(&self, f: &mut Formatter) -> Result {
f.write(format!("{}{}{}{}", self.name, COLON, SP, self.value).as_bytes())
}
}
impl Header {
/// Creates ah `Header`
pub fn new(name: &str, value: &str) -> Header {
Header{name: name.to_string(), value: value.to_string()}
}
}
#[cfg(test)]
mod test {
use super::Header;
#[test]
fn test_new() {
assert_eq!(
Header::new("From", "me"),
Header{name: "From".to_string(), value: "me".to_string()}
);
}
#[test]
fn test_fmt() {
assert_eq!(
format!("{}", Header::new("From", "me")),
"From: me".to_string()
);
}
}

195
src/mailer/mod.rs Normal file
View File

@@ -0,0 +1,195 @@
// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Simple email (very incomplete)
use std::fmt::{Show, Formatter, Result};
use time::{now, Tm};
use mailer::header::{ToHeader, Header};
use mailer::address::ToAddress;
use common::CRLF;
use sendable_email::SendableEmail;
pub mod header;
pub mod address;
/// Simple email representation
#[deriving(PartialEq,Eq,Clone)]
pub struct Email {
/// Array of headers
headers: Vec<Header>,
/// Message body
body: String,
/// The enveloppe recipients addresses
to: Vec<String>,
/// The enveloppe sender address
from: Option<String>,
}
impl Show for Email {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut formatted_headers = String::new();
for header in self.headers.iter() {
formatted_headers.push_str(header.to_string().as_slice());
formatted_headers.push_str(CRLF);
}
f.write(format!("{}{}{}", formatted_headers, CRLF, self.body).as_bytes())
}
}
impl Email {
/// Creates a new empty email
pub fn new() -> Email {
Email{headers: vec!(), body: "".to_string(), to: vec!(), from: None}
}
/// Clear the email content
pub fn clear(&mut self) {
self.headers.clear();
self.body = "".to_string();
self.to.clear();
self.from = None;
}
/// Sets the email body
pub fn body(&mut self, body: &str) {
self.body = body.to_string();
}
/// Add a generic header
pub fn add_header<A: ToHeader>(&mut self, header: A) {
self.headers.push(header.to_header());
}
/// Adds a `From` header and store the sender address
pub fn from<A: ToAddress>(&mut self, address: A) {
self.from = Some(address.to_address().get_address());
self.headers.push(
Header::new("From", address.to_address().to_string().as_slice())
);
}
/// Adds a `To` header and store the recipient address
pub fn to<A: ToAddress>(&mut self, address: A) {
self.to.push(address.to_address().get_address());
self.headers.push(
Header::new("To", address.to_address().to_string().as_slice())
);
}
/// Adds a `Cc` header and store the recipient address
pub fn cc<A: ToAddress>(&mut self, address: A) {
self.to.push(address.to_address().get_address());
self.headers.push(
Header::new("Cc", address.to_address().to_string().as_slice())
);
}
/// Adds a `Reply-To` header
pub fn reply_to<A: ToAddress>(&mut self, address: A) {
self.headers.push(
Header::new("Return-Path", address.to_address().to_string().as_slice())
);
}
/// Adds a `Subject` header
pub fn subject(&mut self, subject: &str) {
self.headers.push(
Header::new("Subject", subject)
);
}
/// Adds a `Date` header with the current time
pub fn date_now(&mut self) {
self.headers.push(
Header::new("Date", Tm::rfc822(&now()).to_string().as_slice())
);
}
/// Adds a `Date` header with the current time
pub fn date(&mut self, time: Tm) {
self.headers.push(
Header::new("Date", Tm::rfc822(&time).to_string().as_slice())
);
}
}
impl SendableEmail for Email {
/// Return the to addresses, and fails if it is not set
fn to_addresses(&self) -> Vec<String> {
if self.to.is_empty() {
panic!("The To field is empty")
}
self.to.clone()
}
/// Return the from address, and fails if it is not set
fn from_address(&self) -> String {
match self.from {
Some(ref from_address) => from_address.clone(),
None => panic!("The From field is empty"),
}
}
fn message(&self) -> String {
self.to_string()
}
}
#[cfg(test)]
mod test {
use super::Email;
use mailer::header::Header;
#[test]
fn test_new() {
assert_eq!(
Email::new(),
Email{headers: vec!(), body: "".to_string(), to: vec!(), from: None}
)
}
#[test]
fn test_body() {
let mut email = Email::new();
email.body("test message");
assert_eq!(
email,
Email{headers: vec!(), body: "test message".to_string(), to: vec!(), from: None}
)
}
#[test]
fn test_add_header() {
let mut email = Email::new();
email.add_header(("X-My-Header", "value"));
assert_eq!(
email,
Email{
headers: vec!(Header::new("X-My-Header", "value")),
body: "".to_string(),
to: vec!(),
from: None
}
)
email.add_header(("X-My-Header-2", "value-2"));
assert_eq!(
email,
Email{
headers: vec!(Header::new("X-My-Header", "value"),
Header::new("X-My-Header-2", "value-2")),
body: "".to_string(),
to: vec!(),
from: None
}
)
}
}