Postfix Advent Calendar 2014 の 13日目の記事です。 現在、12月17日です。毎度遅れてすみません。
Postfix の sendmail
コマンドを MUA として用い、メールを発信する方法について紹介します。
Sendmail や qmail など、ほかの MTA 付属の sendmail
でも概ね同じです。
シェル芸だけで正しくメールを発信できるようになると、色々と便利ですよ。
以下、コマンドラインなどの文字エンコーディングは UTF-8 と仮定します。
設定
Postfix の設定は通常通りで構いません。 メールを発信するだけの MTA を「null クライアント」などと称しますが、 発信のほかに用途がないのであれば、そのような設定をするのがいいと思います。
null クライアントの設定例は Postfix 付属の文書ファイル
STANDARD_CONFIGURATION_README
に記載されています。/etc/postfix/main.cf
は次のようになります。
myhostname = hostname.example.com
myorigin = $mydomain
relayhost = $mydomain
inet_interfaces = loopback-only
mydestination =
master.cf
はデフォルトのままで構いません。
基本的な使い方
基本的には、コマンドライン引数に宛先アドレスを一つ以上指定し、 標準入力にメールメッセージを与えるだけです。 簡単ですね。
$ echo Meowning! |sendmail hotaru@example.ne.jp
上のコマンドラインを hostname.example.com
上のユーザー apache
で実行した場合、だいたい次のような感じのメールが届きます。
Return-Path: <apache@example.com>
To: undisclosed-recipients:;
From: apache@example.com (Apache)
Date: Mon, 15 Dec 2014 22:48:41 +0900 (JST)
Message-Id: <20141215134841.D567A1D80AA@hostname.example.com>
Received: …
Received: …
Meowning!
このように、MUA としての sendmail
は渡されたメールに対して必要最低限のことしかしてくれません。
せいぜい、From:
、Date:
、Message-Id
フィールドを補完したり、
Bcc:
フィールドを削除してくれるくらいです。
エンコーディングなどは関知せず、そのまま送ります。
このため、ユーザーが適切なコマンドラインオプション、引数(宛先)、メールを与えてやる必要があります。
コマンドラインオプションと引数
様々なオプションが用意されていますが、通常用いるのは以下のものだけです。
sendmail [-i] [-f 送信者アドレス] [-t] [宛先アドレス ...]
-i
- 標準入力から与えられるメールメッセージ中のドット
.
だけの行をメールの終端として扱いません。 - デフォルトはドット
.
だけの行を終端と見做し、以降は無視されます。
- 標準入力から与えられるメールメッセージ中のドット
-f 送信者アドレス
- 送信者のメールアドレスです。
- デフォルト値は
実行ユーザーのログイン名@$myorigin
です。 - 「表書き送信者アドレス」(envelope sender address) のことであり、
デフォルト値はメール中の
From:
やSender:
などのフィールド値の影響は受けないことに注意してください。 - 標準入力から与えられるメールのヘッダー部に
From:
フィールドが含まれていない場合、From: このオプションに指定したメールアドレス (実行ユーザーの名前)
が補完されます。
-t
- 宛先のメールアドレスを標準入力から与えられるメールのヘッダー部の
To:
、Cc:
、Bcc:
フィールドから取得します。 - コマンドライン引数にも宛先アドレスが指定されたときは、両方に送られます。
- 宛先のメールアドレスを標準入力から与えられるメールのヘッダー部の
宛先アドレス
- 宛先のメールアドレスです。
- 「表書き宛先アドレス」(envelope recipient address) のことであり、
メール中の
To:
やCc:
などのフィールド値とは直接関係ないことに注意してください。
推奨するコマンドライン
推奨するコマンドラインは次の通りです。 ほとんどの場合はこれでよいと思います。
sendmail -i -f 送信者アドレス 宛先アドレス [...]
-i
は、
メールメッセージ内にドットだけの行が含まれることはあまりないかもしれませんが、
指定しておいたほうがよいでしょう。
-f 送信者アドレス
は、バウンスしたときに実行ユーザー宛に差し戻して嬉しい場面は考えにくいので、
別途バウンスを受けるためのメールアドレスを用意し、それを指定しましょう。
宛先アドレスは、-t
オプションを指定してヘッダーフィールドから取得させるのではなく、
コマンドライン引数で与えることをお薦めします。
To:
などの値にはメールアドレス以外にコメント等が含まれることがあり、
フォーマットは非常に複雑です。
何らかの問題により取得に失敗するかもしれません。
コマンドライン引数に指定したほうが無難です。
推奨するヘッダーフィールド
sendmail
に渡すメールのヘッダー部には、以下を記述することを推奨します。
要は「ふつうのメールに見える」ようにすればいいだけです。
From:
(必須)- 指定しないと
sendmail
実行ユーザーの情報が含まれてしまうので、 明示したほうがよいでしょう。
- 指定しないと
To:
、Cc:
(必須)- 指定しないと
To: undisclosed-recipients:;
となってしまい、ユーザーを混乱させるかもしれません。 - 宛先アドレスはコマンドライン引数で指定するため、
To:
、Cc:
に記載するアドレスは何でも構いません。 - あるユーザー 1人だけに送信するのであれば、その人宛であることを明示するために、 コマンドライン引数と同じメールアドレスでよいでしょう。
- 複数のユーザー宛に送信する場合は、アドレス漏洩を避けるため、
適当な代表者アドレスを記載するとよいでしょう。例えば
info@発信者のメールドメイン
など。
- 指定しないと
Subject:
(必須)- あったほうがよいですよね?
Reply-To:
(任意)From:
とは別のアドレスに返信して欲しいときは記述しましょう。
現実的な使用例
以上を踏まえると、次のようになります。
$ {
echo "From: renge@example.com (MIYAUCHI Renge)"
echo "To: hotaru@example.ne.jp"
echo "Subject: Meowning!"
echo
echo "Good Meowning!"
} |sendmail -i -f renge@example.com bcc@example.com hotaru@example.ne.jp
この例ではメールメッセージをコマンドで生成していますが、 もちろん、ファイルなどで用意するのでも構いません。
日本語をヘッダーに含める
ヘッダーフィールドに日本語を含めるには、 ヘッダー向けの MIME エンコードを施してやる必要になります。 (SMTPUTF8 なる拡張がありますが、現在はまったく普及していないので無視)
文字エンコーディングは旧来の ISO-2022-JP でもいいですし、 現代なら UTF-8 でも問題ないでしょう。ただし、すべてのヘッダーフィールドで 統一したほうが無難です。文字エンコーディングが混在すると誤動作する MUA があります。
nkf による MIME エンコードの例:
$ echo にゃんぱすー |nkf --mime --ic=UTF-8
=?ISO-2022-JP?B?GyRCJEskYyRzJFEkOSE8GyhC?=
$ echo にゃんぱすー |nkf --mime --ic=UTF-8 --oc=UTF-8
=?UTF-8?B?44Gr44KD44KT44Gx44GZ44O8?=
Perl による MIME エンコードの例:
$ echo にゃんぱすー |perl -MEncode -pe 'chomp($_); $_ = encode("MIME-Header-ISO_2022_JP", decode("UTF-8",$_))'; echo
=?ISO-2022-JP?B?GyRCJEskYyRzJFEkOSE8GyhC?=
$ echo にゃんぱすー |perl -MEncode -pe 'chomp($_); $_ = encode("MIME-Header", decode("UTF-8",$_))'; echo
=?UTF-8?B?44Gr44KD44KT44Gx44GZ44O8?=
Perl の場合、改行コードも含めて処理させた場合の結果が不安定なので、
例のように改行コードは取り除いて (chomp($_)
) から処理することをお勧めします。
https://twitter.com/satoh_fumiyasu/status/1202423887453020161
echo あ |perl -MEncode -pe ‘$_ = encode(“MIME-Header-ISO_2022JP”, decode(“UTF-8”,$))’ だと改行も含まれるのに、 echo あ |perl -MEncode -pe ‘$_ = encode(“MIME-Header”, decode(“UTF-8”,$_))’ だと含まれないの、何でなの…と思ったら、後者は改行も含めてエンコードされてしまうのか…。
https://twitter.com/satoh_fumiyasu/status/1202426064875618304
後者、Perl 5.8.4 だと改行は含めずにヘッダー MIME エンコードして改行が捨てられるんだけど。
ISO-2022-JP か UTF-8 かに依っても結果が異なるだけでなく、Perl バージョンに依っても異なるんですががが。
改行コードを含めずに渡すのが無難ってことかね。
日本語を本文に含める
文字エンコーディングを ISO-2022-JP にするなら、そのまま突っ込めばいいです。
ただし、Content-Type:
ヘッダーフィールドで文字エンコーディングを明示しましょう。
このとき MIME-Version:
ヘッダーフィールドも必須です。
…他のヘッダーフィールド…
Content-Type: text/plain; charset=ISO-2022-JP
MIME-Version: 1.0
…ISO-2022-JP エンコードされた本文…
文字エンコーディングを UTF-8 にする場合は、Base64 や Quoted-Printable
形式でエンコードする形式が一般的です。
Base64 であれば GNU coreutils の base64
コマンドや nkf の --base64
オプションが利用できます。
$ echo 本文テキスト |base64
…
$ echo 本文テキスト |nkf --base64 --ic=UTF-8 --oc=UTF-8
…
UTF-8 + Base64 (または Quoted-Printable) の場合は
Content-Transfer-Encoding:
フィールドで明示する必要があります。
…他のヘッダーフィールド…
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64
MIME-Version: 1.0
…UTF-8 + Base64 エンコードされた本文…
現代の MTA と MUA であれば、Base64 などエンコードなしで、UTF-8 のまま本文に突っ込んでも問題ありません。
…他のヘッダーフィールド…
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
…UTF-8 エンコードされた本文…
日本語を含む使用例
以上を踏まえると、次のようになります。
ISO-2022-JP の場合:
$ {
echo "From: renge@example.com (MIYAUCHI Renge)"
echo "To: hotaru@example.ne.jp"
echo "Subject: `echo にゃんぱすー |nkf --mime --ic=UTF-8`"
echo "Content-Type: text/plain; charset=ISO-2022-JP"
echo "MIME-Version: 1.0"
echo
{
echo "にゃんぱすー!"
echo "-- "
echo "れんげ"
} |nkf --ic=UTF-8 --oc=ISO-2022-JP -x -m0
} |sendmail -i -f renge@example.com bcc@example.com hotaru@example.ne.jp
UTF-8 の場合:
$ {
echo "From: renge@example.com (MIYAUCHI Renge)"
echo "To: hotaru@example.ne.jp"
echo "Subject: `echo にゃんぱすー |nkf --mime --ic=UTF-8 --oc=UTF-8`"
echo "Content-Type: text/plain; charset=UTF-8"
echo "Content-Transfer-Encoding: 8bit"
echo "MIME-Version: 1.0"
echo
echo "にゃんぱすー!"
echo "-- "
echo "れんげ"
} |sendmail -i -f renge@example.com bcc@example.com hotaru@example.ne.jp
番外: nkf の推奨オプション
nkf を利用するとき指定したほうがよい、あるいは指定を考慮すべきオプションを紹介しておきます。 デフォルトで文字エンコーディング変換以外の変換処理がされるため、これを抑制します。
-x
- JIS X 0201 カナ(いわゆる「半角カナ」)を JIS X 0208 カナ(いわゆる「全角カナ」)に変換しません。
-m0
- ヘッダー MIME エンコードされた文字列をデコードしません。
指定しなくても問題ない場合もありますが、明示しておいたほうが無難です。
ところで、12月25日はクリスマスな上に、
OSS 界隈で地味に活躍されているふみやすさんの誕生日ですね!
っ http://www.amazon.co.jp/registry/wishlist/27M7TV8CEEF6G?sort=priority
逆に、あなたの書いた OSS や Blog や Advent Calendar が気に入ったら何か送りたく なってしまうかもしれないので、プロフィールや Web サイトに あなたの Amazon 欲しいものリストの URL を貼っておいてくださいね!
私が勤める OSSTech っていう某弊社で社員募集しているようです。 人材紹介会社を介さなければ、入社後に 20万円のボーナス! 「ふみやすっていう人に紹介された」と言ってもらえると私にもボーナス!! → https://www.osstech.co.jp/recruit/
よろしければ、これまで参加した/参加予定のほかの Advent Calendar もどうぞ。
- Ansible Advent Calendar 2023
- シェル芸 Advent Calendar 2023
- 闇の魔術に対する防衛術 Advent Calendar 2023
- Ansible Advent Calendar 2023
- Ansible Advent Calendar 2020
- DNS温泉 Advent Calendar 2019
- OSSTech Advent Calendar 2019
- Ansible Advent Calendar 2018
- OSSTech Advent Calendar 2018
- Debian/Ubuntu Advent Calendar 2017
- Linux Advent Calendar 2017
- Shell Script Advent Calendar 2017
- Shell Script Advent Calendar 2016
- OpenLDAP と仲間たち Advent Calendar 2015
- Postfix Advent Calendar 2014
- 拡張 POSIX シェルスクリプト Advent Calendar 2013