Email delivery library for Erlang — composable email builder with swappable adapter backends.
- Builder — functional, chainable email construction with address normalization
- Attachments — from file path, binary data, or inline with content-id
- Mailer — behaviour-based mailer modules with validation on delivery
- Adapters — SMTP, SendGrid, Mailgun, Amazon SES, logger, and test
- Content Types — automatic MIME type detection for attachments
-module(my_mailer).
-behaviour(hikyaku_mailer).
-export([config/0, deliver/1]).
config() ->
#{
adapter => hikyaku_adapter_smtp,
relay => <<"smtp.example.com">>,
port => 587,
username => <<"user@example.com">>,
password => <<"secret">>,
tls => always
}.
deliver(Email) ->
hikyaku_mailer:deliver(?MODULE, Email).-include_lib("hikyaku/include/hikyaku.hrl").
Email = hikyaku_email:new(),
Email1 = hikyaku_email:from(Email, {<<"Alice">>, <<"alice@example.com">>}),
Email2 = hikyaku_email:to(Email1, <<"bob@example.com">>),
Email3 = hikyaku_email:subject(Email2, <<"Hello!">>),
Email4 = hikyaku_email:text_body(Email3, <<"Hi Bob">>),
Email5 = hikyaku_email:html_body(Email4, <<"<b>Hi Bob</b>">>),
{ok, _} = my_mailer:deliver(Email5).Addresses accept a binary (<<"bob@example.com">>), a {Name, Address} tuple, or a #hikyaku_address{} record.
Use to/2, cc/2, bcc/2 to append recipients, or put_to/2, put_cc/2, put_bcc/2 to replace the entire list.
%% From file path (content type auto-detected)
Pdf = hikyaku_attachment:from_path(<<"/tmp/report.pdf">>),
%% From binary data
Csv = hikyaku_attachment:from_data(<<"data.csv">>, CsvBin),
%% Inline image with content-id
Logo = hikyaku_attachment:inline(<<"logo">>, <<"/tmp/logo.png">>),
Email6 = hikyaku_email:attachment(Email5, Pdf),
Email7 = hikyaku_email:attachment(Email6, Logo).from_path/2 and from_data/3 accept an options map: #{content_type => binary(), filename => binary()}.
| Adapter | Description | Config |
|---|---|---|
hikyaku_adapter_smtp |
SMTP via gen_smtp | relay, port, username, password, ssl, tls |
hikyaku_adapter_sendgrid |
SendGrid v3 API | api_key, http_client |
hikyaku_adapter_mailgun |
Mailgun Messages API | api_key, domain, base_url, http_client |
hikyaku_adapter_ses |
Amazon SES v2 API | access_key, secret_key, region, http_client |
hikyaku_adapter_logger |
Logs emails via logger | level |
hikyaku_adapter_test |
Sends to a process | pid |
config() ->
#{
adapter => hikyaku_adapter_mailgun,
api_key => <<"key-xxx">>,
domain => <<"mg.example.com">>,
base_url => <<"https://api.eu.mailgun.net">> %% optional, defaults to US region
}.config() ->
#{
adapter => hikyaku_adapter_ses,
access_key => <<"AKIA...">>,
secret_key => <<"...">>,
region => <<"us-east-1">>
}.SES uses the v2 JSON API for simple emails and automatically falls back to raw MIME encoding when attachments are present. Authentication uses AWS Signature V4 — no external dependencies required beyond OTP crypto.
-include_lib("hikyaku/include/hikyaku.hrl").
-include_lib("eunit/include/eunit.hrl").
-behaviour(hikyaku_mailer).
config() ->
#{adapter => hikyaku_adapter_test, pid => self()}.
send_test() ->
Email = hikyaku_email:to(
hikyaku_email:from(
hikyaku_email:subject(hikyaku_email:new(), <<"Test">>),
<<"sender@test.com">>
),
<<"recipient@test.com">>
),
{ok, _} = hikyaku_mailer:deliver(?MODULE, Email),
receive
{hikyaku_email, Received} ->
?assertEqual(<<"Test">>, Received#hikyaku_email.subject)
after 1000 ->
error(timeout)
end.- Erlang/OTP 27+