package letters
Install
dune-project
Dependency
Authors
Maintainers
Sources
sha256=5cbda38f8c891ae84b55aa27f07d598ea6e0251e4e4bd1435b3fde904efc935a
sha512=06a8612473331bcbcaa6e18743d53e9c3a94f82778ce2883327959c4d4be7b785a975fdad93ae34fd2a15cb1f66635346b10dc54a68cef5fbb0fdd750ff1b9e5
doc/README.html
✉ Letters ·

Letters is a library for creating and sending emails over SMTP using Lwt.
Table of Contents
Use
Purpose of the library is to make it easier to send emails when building systems using OCaml. Currently the API consists of three parts:
- configuration
- building email messages
- sending email messages
Whole API is in lib/letters.mli that contains also some additional documentation.
Keep in mind that this library is in its early days and the API is changing with every release. Also this is tested only on Linux based systems and testing is pretty weak and manual. Though the library has been used successfully.
Configuration
Most simple use case would look something like:
let conf = Config.make ~username:"myuser" ~password:"mypasswd" ~hostname:"smtp.ethereal.email" ~with_starttls:trueThis will use port 587, uses STARTTLS for encryption and tries automatically find CA certificates for verifying server connection.
Port 587 is default when using STARTTLS. If you set ~with_starttls:false, then the default port will be 465.
This library does not support SMTP connections without TLS encryption or authentication. For TLS encryption, this library uses ocaml-tls.
If you want to change the server port you can do it with Config.set_port (passing None causes default port to be used):
let conf = Config.make ~username:"myuser" ~password:"mypasswd" ~hostname:"smtp.ethereal.email" ~with_starttls:true
|> Config.set_port (Some 2525)If the CA certificate auto-detection does not work for you (it's very naïve implementation), you can define path to a certificate bundle or to a single PEM encoded certificate, or you can define path to a folder containing multiple PEM encoded certificate files.
To use a CA certificate bundle (each included certificate needs to be PEM encoded):
let conf = Config.make ~username:"myuser" ~password:"mypasswd" ~hostname:"smtp.ethereal.email" ~with_starttls:true
|> Config.set_ca_cert "/etc/ssl/certs/ca-certificates.crt"To use a single PEM encoded CA certificate:
let conf = Config.make ~username:"myuser" ~password:"mypasswd" ~hostname:"smtp.ethereal.email" ~with_starttls:true
|> Config.set_ca_cert "/etc/ssl/certs/DST_Root_CA_X3.pem"To use all PEM encoded certificate files from a folder:
let conf = Config.make ~username:"myuser" ~password:"mypasswd" ~hostname:"smtp.ethereal.email" ~with_starttls:true
|> Config.set_ca_path "/etc/ssl/certs/"Building emails
Building an email is separated into its own step so that you can use mrmime to generate more complex emails when this simplified API does not work for you.
To use our provided API, you can build three kinds of emails:
Plain, plain textHtml, HTML onlyMixed, multipart/alternative containing both: plain text and HTMl segments
If you're not sure, either use Plain or Mixed.
Example of building a plain text email:
let sender = "harry@example.com" in
let recipients =
[
To "larry@example.com";
Cc "bill@example.com";
Bcc "dave@example.com";
]
in
let subject = "HTML only test email" in
let body =
Plain
{|
Hi there,
This is a test email from https://github.com/oxidizing/letters
Regards,
The Letters team
|}
in
let mail = build_email ~from:sender ~recipients ~subject ~body inExample of building an HTML only email:
let sender = "harry@example.com" in
let recipients =
[
To "larry@example.com";
Cc "bill@example.com";
Bcc "dave@example.com";
]
in
let subject = "HTML only test email" in
let body =
Html
{|
<p>Hi there,</p>
<p>
This is a test email from
<a href="https://github.com/oxidizing/letters">letters</a>
<p>
Regards,<br>
The Letters team
</p>
|}
in
let mail = build_email ~from:sender ~recipients ~subject ~body inExample of building an email with plain text and HTMl segments:
let sender = "harry@example.com" in
let recipients =
[
To "larry@example.com";
Cc "bill@example.com";
Bcc "dave@example.com";
]
in
let subject = "HTML only test email" in
let text =
{|
Hi there,
This is a test email from https://github.com/oxidizing/letters
Regards,
The Letters team
|}
in
let html =
{|
<p>Hi there,</p>
<p>
This is a test email from
<a href="https://github.com/oxidizing/letters">letters</a>
<p>
Regards,<br>
The Letters team
|}
in
let mail = build_email ~from:sender ~recipients ~subject ~body:(Mixed (text, html, None)) inLetters.build_email returns result so you need to map it accordingly:
let mail = build_email ~from:sender ~recipients ~subject ~body:(Mixed (text, html, None)) in
match mail with
| Ok message -> do_something message
| Error reason -> handle_error reasonSending emails
Sending is single API call Letters.send that looks like following (when using config, sender, recipients and message from previous examples):
send ~config ~sender ~recipients ~messageReturn type is Lwt.t so you need to run it with appropriate Lwt routines.
Examples
See service-test/test.ml for complete examples that are using ethereal.email service to test sending emails.
Development
Setup
opam switch create . ocaml-base-compiler.4.08.1
eval $(opam env)
opam install --deps-only -y . --with-testBuild
dune buildTests
Unit tests
Run with default test target of dune:
dune build @runtestThese tests are still somewhat far from good and you need to validate all results manually by checking the test output logs.
Service tests
These tests are somewhat slow and fragile and because of that these are expected to be run manually.
First create ethereal.email account and store account details
curl -d '{ "requestor": "letters", "version": "dev" }' "https://api.nodemailer.com/user" -X POST -H "Content-Type: application/json" > ethereal_account.jsonCurrently using ethereal.email service requires non-released version of colombe and you need to check out the project, commit edf757c58fce58c170c63e8a92d3bc81fe4d32ff contains the needed fix. Then the version with the fix needs to be pinned in the build env:
# Move to folder where colombe is checked out
pushd /path/to/colombe
# Switch to correct git commit in colombe repo
git switch --detach edf757c58fce58c170c63e8a92d3bc81fe4d32ff
# Switch to use same opam env that is used by letters
eval "$(opam env --switch $(dirs | cut -d ' ' -f 2) --set-switch)"
# Pin this specific version of colombe (and all related packages)
opam pin .
# Finally, return back to letters project
popdThen execute these tests (actually this runs all tests):
dune build @runtest-allAnd finally review that the email is correctly generated in the service:
- login to https://ethereal.email/login using credentials from the
ethereal_account.json - check the content of messages: https://ethereal.email/messages
Credits
This project is build on colombe and mrmime libraries and use facteur as starting point.
License
Copyright (c) 2020 Miko Nieminen
Distributed under the MIT License.