RustからTwilio SendGridのメールを送信する方法
- 2022年9月15日
- by 菊田 洋一
- Category: 技術ネタ

Twilio SendGridサポートチームの菊田(@kikutaro_)です。最近、プログラミング言語の「Rust」を触り始めました。勉強の一環としてSendGridを使ったメール送信を試してみたので、ブログにまとめたいと思います。
Windows 10のDocker上に構築した以下の環境を利用しました。
- Debian 11.4
- Rust 1.63.0
lettreを使った送信
テキストメール
SMTPによる送信はRust向けのメール送信ライブラリlettreを使いました。まずはRust標準のパッケージマネージャ「Cargo」で新規にプロジェクトを作成してlettreを追加します。
cargo new smtp
Cargo.tomlに以下の内容を追記します。
|
[dependencies] lettre = "0.10.0" |
ビルドするとなぜかエラーになってしまいました。
cargo build Compiling openssl-sys v0.9.75 error: failed to run custom build command for `openssl-sys v0.9.75`
証明書関連のライブラリが足りないのが原因のようです。私の環境では最終的にpkg-configとlibssl-devをインストールすることで解決しました。
apt-get install pkg-config libssl-dev
lettreのExampleを元に、認証や接続の情報をSendGridのものに変更します。
use lettre::transport::smtp::authentication::Credentials;
use lettre::{Message, SmtpTransport, Transport};
fn main() {
let email = Message::builder()
.from("FromName <from@example.com>".parse().unwrap())
.to("ToName <to@example.com>".parse().unwrap())
.subject("Rustでメール送信!")
.body(String::from("RustからSendGridのSMTPで送ってるよ!"))
.unwrap();
let creds = Credentials::new("apikey".to_string(), "SG.xxxxxxxx".to_string());
let mailer = SmtpTransport::relay("smtp.sendgrid.net")
.unwrap()
.credentials(creds)
.build();
match mailer.send(&email) {
Ok(_) => println!("送信成功"),
Err(e) => panic!("送信失敗: {:?}", e),
}
}
(参考)
ビルドエラーが発生しないことを確認して実行します。
rust build rust run

メールが無事に届きました!思っていたよりかなり簡単です。
マルチパートメール
今度はHTMLパートとテキストパートの両方を含むマルチパートメールを送信します。lettreではマルチパートを直感的に実装できるのでありがたいです(コード27行目)。
use lettre::transport::smtp::authentication::Credentials;
use lettre::{
message::{header, MultiPart, SinglePart},
SmtpTransport, Message, Transport,
};
fn main() {
let html = r#"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" /><!--[if !mso]><!-->
<meta http-equiv="X-UA-Compatible" content="IE=Edge" /><!--<![endif]-->
</head>
<body>
<div style="display: flex; flex-direction: column; align-items: center;">
<h2>RustからSendGridのSMTPで送ってるよ!</h2>
<h4>HTMLパート</h4>
</div>
</body>
</html>"#;
let email = Message::builder()
.from("FromName <from@example.com>".parse().unwrap())
.to("ToName <to@example.com>".parse().unwrap())
.subject("Rustでマルチパートメール送信!")
.multipart(
MultiPart::alternative()
.singlepart(
SinglePart::builder()
.header(header::ContentType::TEXT_PLAIN)
.body(String::from("テキストパート")),
)
.singlepart(
SinglePart::builder()
.header(header::ContentType::TEXT_HTML)
.body(String::from(html)),
)
)
.unwrap();
let creds = Credentials::new("apikey".to_string(), "SG.xxxxxxxx".to_string());
let mailer = SmtpTransport::relay("smtp.sendgrid.net")
.unwrap()
.credentials(creds)
.build();
match mailer.send(&email) {
Ok(_) => println!("送信成功"),
Err(e) => panic!("送信失敗: {:?}", e),
}
}
受信したメールを確認するとHTMLパートの内容が無事に表示されました。

テキストパートは受信したメールのソースで確認してみましょう。マルチパートメールのテキストとHTMLの区切りはboundaryで定義されています。受信したメールでは「boundary="inhjyJTg8beDfQ6gmb4kJyd5N0WQwCN8qF15HEHg"」となっていたので、この文字列を検索します。

「Content-Type: text/plain」の部分がテキストパートです。base64でエンコードされているのでデコードします。
echo '44OG44Kt44K544OI44OR44O844OI' | base64 -d テキストパート
送信した内容と一致していますね。マルチパートメールが送れたことを確認できました。
sendgrid-rsを使った送信
続いてWeb APIによる送信を試しました。Rustにはhyperやreqwest、surfなど様々なHTTPクライアントがあるのでどれが良いのか悩んでいたところ、sendgrid-rsというラッパーライブラリをみつけました。非公式のライブラリではありますが、公式サイトでも紹介されています。
use sendgrid::v3::*;
fn main() {
let p = Personalization::new(Email::new("to@example.com"));
let message = Message::new(Email::new("from@example.com"))
.set_subject("Rustでメール送信!")
.add_content(
Content::new()
.set_content_type("text/plain")
.set_value("sendgrid-rsを使ってWeb APIから送ってるよ!"),
)
.add_personalization(p);
let api_key = "SG.xxxxxxxxx".to_string();
let sender = Sender::new(api_key);
let code = sender.send(&message);
println!("{:?}", code);
}
他言語の公式ライブラリ並みに簡単な実装で送信できました。あくまでも非公式のライブラリなので、実際の運用で利用する場合には事前の動作確認やサポート状況をよく確認してください。
コード
今回書いたコードはすべてこちらにまとめました。
おわりに
最近Rustに関する情報をよく見かけるので勉強を兼ねて触ってみました。C言語やC++に置き換わる言語とも聞いていたのでとっつきにくいのかな…?と思っていましたが、Cargoのようなパッケージマネージャも標準で備えられていて、モダンで書きやすい印象でした。今後さらに勉強していきたいと思います。


