#regex #delivery #agents #header #data #byte

mda

A library for creating custom Mail Delivery Agents

2 releases

0.1.1 Oct 6, 2019
0.1.0 Oct 1, 2019

#236 in Email

MPL-2.0 license

56KB
843 lines

mda-rs

mda-rs is a Rust library for writing custom Mail Deliver Agents.

Documentation

The detailed module documentation, including code examples for all features, can be found at https://docs.rs/mda.

Usage

Add this to your Cargo.toml:

[dependencies]
mda = "0.1"

If you are using Rust 2015 add the following to your crate root file (Rust 2018 doesn't require this):

extern crate mda;

See examples/personal-mda.rs for an example that uses mda-rs.

License

This project is licensed under the Mozilla Public License Version 2.0 (LICENSE or https://www.mozilla.org/en-US/MPL/2.0/).


lib.rs:

The mda crate provides a library for writing custom Mail Deliver Agents. It supports local delivery to maildirs, access to normalized email byte data for easier processing, and access to individual header fields.

Email data normalization involves ensuring header fields are in single lines, decoding text parts of the message that use some kind of transfer encoding (e.g., base64), and converting all text to UTF-8. The original (non-normalized) email data is used during delivery.

This crate also exposes convenience methods for regular expression searching and processing/filtering of emails.

Email construction

The Email struct is the basic abstraction of the mda crate. To construct an Email use the Email::from_stdin or Email::from_vec method.

use mda::Email;
let email = Email::from_stdin()?;
let email = Email::from_vec(vec![97, 98, 99])?;

Email delivery

Use the Email::deliver_to_maildir method to deliver the email to local maildir directories. Note that the original (non-normalized) email data is used during delivery.

use mda::Email;
let email = Email::from_stdin()?;
email.deliver_to_maildir("/my/maildir/path")?;
email.deliver_to_maildir("/my/other/maildir/path")?;

Accessing email header fields

Use the Email::header_field and Email::header_field_all_occurrences methods to access the email header fields. Any MIME encoded words in the header field values are decoded and the field value is converted to UTF-8.

use mda::Email;
let email = Email::from_stdin()?;
let to = email.header_field("To").unwrap_or("");
if to.contains("me@example.com") {
    email.deliver_to_maildir("/my/maildir/path")?;
}

Searching with regular expressions

The EmailRegex trait provides convenience methods for searching the header, the body or the whole email with regular expressions. The convenience functions use case-insensitive, multi-line search (^ and $ match beginning and end of lines). If the above don't match your needs, or you require additional functionality, you can perform manual regex search using the email data.

use mda::{Email, EmailRegex};
let email = Email::from_stdin()?;
if email.header().search(r"^To:.*me@example.com")? {
    email.deliver_to_maildir("/my/maildir/path")?;
}

Processing and filtering the email with external programs

Use the Email::filter and Email::from_stdin_filtered methods to filter the email, in both cases creating a new email.

use mda::Email;
// Filtering directly from stdin is more efficient.
let email = Email::from_stdin_filtered(&["bogofilter", "-ep"])?;
let bogosity = email.header_field("X-Bogosity").unwrap_or("");
if bogosity.contains("Spam, tests=bogofilter") {
    email.deliver_to_maildir("/my/spam/path")?;
}
// We can also filter at any other time.
let email = email.filter(&["bogofilter", "-ep"])?;

To perform more general processing use the Email::process method:

use mda::Email;
let email = Email::from_stdin()?;
let output = email.process(&["bogofilter"])?;
if let Some(0) = output.status.code() {
    email.deliver_to_maildir("/my/spam/path")?;
}

Access to byte data

Use the Email::header, Email::body, Email::data methods to access the normalized byte data of the header, body and whole email respectively.

Normalization involves ensuring header fields are in single lines, decoding text parts of the message that use some kind of transfer encoding (e.g., base64), and converting all text to UTF-8 character encoding.

If for some reason you need access to non-normalized data use Email::raw_data.

use std::str;
use mda::Email;
let email = Email::from_stdin()?;
let body_str = String::from_utf8_lossy(email.header());

if body_str.contains("FREE BEER") {
    email.deliver_to_maildir("/my/spam/path")?;
}

Decide delivery durability vs speed trade-off

Use the Email::set_delivery_durability to decide which DeliveryDurability method to use. By default the most durable (but also slower) method is used.

use mda::{Email, DeliveryDurability};
let mut email = Email::from_stdin()?;
email.set_delivery_durability(DeliveryDurability::FileSyncOnly);

Dependencies

~7MB
~183K SLoC