6 releases (3 breaking)
0.4.0 | Jan 15, 2020 |
---|---|
0.3.1 | Dec 10, 2019 |
0.2.1 | Dec 9, 2019 |
0.1.1 | Dec 9, 2019 |
#800 in Testing
20KB
271 lines
trapmail
trapmail
is a sendmail
replacement for unit- and integration-testing that captures incoming mail and stores it on the filesystem. See the documentation for details.
lib.rs
:
trapmail: A sendmail replacement for integration testing
trapmail
is a sendmail
replacement for unit- and integration-testing that captures incoming
mail and stores it on the filesystem. Test cases can inspect the "sent" mails.
Use case
trapmail
is intended for black-box testing systems that use the systemwide sendmail
instance
to send emails. Example:
trapmail
is installed and either replacessendmail
on the test system/container, or the application being tested is configured to usetrapmail
as itssendmail
binary.- An integration test (written in Rust) triggers various processes that cause the application
to send mail, which is collected inside
TRAPMAIL_STORE
. - Having access to
TRAPMAIL_STORE
as well, thetrapmail
library can be used inside the integration test to check if mail was queued as expected.
CLI
trapmail
's commandline aims to mimick the original sendmail
arguments, commonly also
implemented by other MTAs like
Exim or Postfix.
When trapmail
receives a message, it stores it along with metadata a JSON file in the
directory named in the TRAPMAIL_STORE
environment variable, falling back to /tmp
if
not found. Files are named trapmail_PPID_PID_TIMESTAMP.json
, where PPID
is the parent
process' PID, PID
trapmails PID
at the time of the call and TIMESTAMP
a microsecond
accurate timestamp.
Command-line options
Currently, trapmail
does not "support" all the same command-line options that sendmail
supports (all options are ignored, but logged). If you run into issues due to an
unsupported option, feel free to open a PR to get it added.
Example
$ trapmail --debug -i -t foo@bar
To: Santa Clause <santa@example.com>
From: Marc <marc@example.com>
Subject: Please remove me from the naughty list.
Example body.
^D
Mail written to "/tmp/trapmail_1575911147313470_5913_6299.json"
The resulting mail is (somewhat readable) JSON, but can also be dumped using the cli tool:
$ trapmail --dump /tmp/trapmail_1575911147313470_5913_6299.json
Mail sent on 2019-12-09 17:05:47.000313 UTC from PID 6299 (PPID 5913).
CliOptions {
debug: true,
ignore_dots: true,
inline_recipients: true,
addresses: [
"foo@bar",
],
dump: None,
}
To: Santa Claus <santa@example.com>
From: Marc <marc@example.com>
Subject: Please remove me from the naughty list.
Example body.
Concurrency
While trapmail
avoids collisions between stored messages from different processes due to its
naming scheme, it is important to remember that it has no way to access any data of the test
itself (the PPID is from the application-under-tests's PID, not the test binary).
Providing different TRAPMAIL_STORE
targets allows for namespacing the data, but it may not
always be possible to ensure this variable is set per test on a closed system.
API
The trapmail
crate comes with a command-line application as well as a library. The
library can be used in tests and applications to access all data that trapmail
writes.
A minimal example to read the contents of the current trapmail folder:
use trapmail::MailStore;
// Load mail from the default mail directory.
let store = MailStore::new();
for load_result in store.iter_mails().expect("could not open mail store") {
let mail = load_result.expect("could not load mail from file");
println!("{}", mail);
}
Dependencies
~6.5–9MB
~157K SLoC