「Rustでメールを送る」と聞くと、なんとなく難しそうな印象を持つ人は多いと思います。
そもそも、Rust自体が難しいと思ってる人が多いと思います。
でも実際にやっていることは、とても単純です。
宛先・件名・本文を用意して、SMTPサーバに渡す
これだけです。
メールはただのデータ
まず、メールをデータとして表すとこうなります。
struct EmailPayload {
to: String,
subject: String,
body: String,
}
メールに必要な情報はこれだけです。
- 宛先
- 件名
- 本文
HTMLメールや添付ファイルを考えない限り、
「メール」とは本質的にはこの3要素の組み合わせでしかありません。
Rustでメールを送るとは、この構造を配送する処理を書くだけ、ということになります。
lettreでメールを組み立てる
RustでSMTPを扱う場合、lettre クレートを使うのが一般的です。
まずはメールそのものを組み立てます。
use lettre::Message;
let email = Message::builder()
.from("Example <noreply@example.com>".parse().unwrap())
.to("user@example.com".parse().unwrap())
.subject("Hello from Rust")
.body("This mail was sent by Rust.")
.unwrap();
ここでやっていることは、荷物の準備です。
- 誰から
- 誰へ
- どんな件名で
- どんな本文を送るか
これをコードで表現しています。
SMTPで送信する
次に、SMTPサーバへ接続するためのトランスポートを用意します。
use lettre::transport::smtp::authentication::Credentials;
use lettre::{AsyncSmtpTransport, Tokio1Executor};
let mailer = AsyncSmtpTransport::<Tokio1Executor>::relay("smtp.example.com")
.unwrap()
.credentials(Credentials::new(
"username".to_string(),
"password".to_string(),
))
.build();
そして、先ほど組み立てたメールを送信します。
mailer.send(email).await?;
なぜ難しく見えるのか
実際のプロダクションコードでは、ここにいろいろな処理が追加されます。
- 環境変数からSMTP設定を読む
- 失敗したらリトライする
- 非同期ワーカーとして常駐させる
- キューと連携する
- ログを出す
こうした要素が積み重なることで、「メール送信」が急に重たく見えてきます。
ですが、それらはすべて運用のための都合です。
「メールを送る」という行為そのものが難しいわけではありません。
コアは常にこれだけです。
let email = Message::builder()
.to(payload.to.parse().unwrap())
.subject(payload.subject)
.body(payload.body)
.unwrap();
mailer.send(email).await?;
これを見れば、メール送信が単なるI/O処理であることが分かると思います。
メール送信の仕組みについては下記の記事で詳しく紹介しています。さらに知りたくなったらぜひお読みください。