電子メイルはそのメッセージがファイルとして保存されるだけではなく, メッセージの内容を標準入力としたプログラムの起動も行なえる。
qmailでは,各ユーザ宛のメイルの配送先を
~user/.qmail ファイルで決定する。
このファイルは dot-qmail(5) ファイル形式で記述する。1行1エントリで
以下のいずれかを書ける。
| 行頭文字 | 種類 | 例 |
|---|---|---|
# | コメント | # メモ |
| | プログラム | |./program arg |
. または /(スラッシュで終わらない) |
mbox形式のファイル | ./mbox |
. または /(スラッシュで終わる) |
maildir形式のディレクトリ | ./maildir/ |
| & | 転送メイルアドレス | &taro@example.ac.jp |
また,dot-qmail ファイルとして
~user/.qmail-ext があると,
user-ext という宛先の配送先として利用する。
これを拡張アドレスといい,ext の部分を
拡張子という。また,ext を default にした
~user/.qmail-default
というファイルを作ると,対応する dot-qmail ファイルがない場合の
デフォルトの宛先となる。
| で始まる行は,すぐ後ろに書いたプログラムを
書いてあるとおりに起動する。このとき以下の環境変数が自動的に
設定された状態でプログラムが呼ばれる。
| 環境変数 | 値の意味 |
|---|---|
SENDER | エンベロープsender |
RECIPIENT | 受信者アドレス |
USER | 受信者のユーザ名 |
HOME | 受信者のホームディレクトリ |
HOST | 受信アドレスのドメイン部 |
LOCAL | 受信アドレスのローカル部 |
EXT | 拡張子部分(ユーザ名以降最初のハイフン以降) |
EXT2 | $EXTの1個目のハイフン以降 |
EXT3 | $EXTの2個目のハイフン以降 |
EXT4 | $EXTの3個目のハイフン以降 |
DEFAULT | default でマッチした文字列 |
上記の変数をうまく利用すればメイル処理プログラムが効率的に作れる。 簡単な例として,送信者に「ありがとう」とだけ返すプログラムを作る。
メイルアドレスは user-39 で作る。
echo '| ./pf3/thankyou.rb' > ~/.qmail-39
ホームディレクトリから見て ./pf3/thankyou.rb
の名前で送信者($SENDER)にメイルを送るRubyプログラムを
作る。その前にメイルを送信するコマンドについて調べる。
メイルを送信するための原始的なプログラム sendmail を利用するとプログラムでメイル送信が容易に行なえる。
sendmail -f from@add.ress to@reci.pie.nt...
これで標準入力を読んだ結果を送信する。ヘッダと本文を正しく入れて 送信してみる。
sendmail -f 自分のアドレス 自分のアドレス
To: 自分のアドレス
From: 自分のアドレス
Subject: test
Hello!
[C-d]
メイルヘッダのフィールド値に日本語を入れたい場合はMIMEエンコード する必要がある。また,本文もJISコード(ISO-2022-JP)に変換しておく 必要がある。いずれも nkf ライブラリで変換できる。元の文字列をMIMEエンコードするには
NKF.nkf('-M', String)
とし,JISコードに変換するには
NKF.nkf('-j', String)
とする。日本語Subject付の日本語メッセージを送る簡単な プログラムは以下のようになる。
#!/usr/bin/env ruby
require 'nkf'
subj = '日本語サブジェクト'
body = 'こんにちは,
さようなら。'
if ARGV[0] == nil then
STDERR.puts "送り先アドレスを指定して下さい。"
STDERR.puts " 例: #{$0} toaddress@example.jp"
exit 1
end
command = sprintf("| sendmail %s", ARGV[0])
header = sprintf("To: %s\nSubject: %s\n\n",
ARGV[0], NKF.nkf('-M', subj))
open(command, "w") do |mail|
mail.print header
mail.print NKF.nkf('-j', body)
end
~/.qmail-39 に指定したプログラムで,
送信者に「ありがとう」とだけ返すプログラムを作成してみる。
送信者はスクリプト起動時の環境変数 SENDER から
取得し,そこにメイルを返すようにするのが簡単である。
プログラムは
~/.qmail-39 への送信により
qmailデーモンから起動される。このとき標準入力を読むと
メイル本文の1行目から順に入る。
送信者のアドレスが環境変数 SENDER
に入っているのでこれをスクリプトから送るメイルの
宛先とする。
スクリプトが走るきっかけとなった受信アドレスが
環境変数 RECIPIENT に入っているので,
これをスクリプトから送るメイルの送信者アドレスとする。
SubjectはMIMEエンコードし,本文はJISコード変換してから送る。
という流れで作成する。
環境変数は,Rubyの変数 ENV にハッシュとして
入っている。たとえば,ENV["FOO"] は,環境変数
FOO が定義されている場合はその値が,定義されていない場合は
nil が返る。
#!/usr/bin/env ruby
require 'nkf'
sender = ENV['SENDER']
rcpt = ENV['RECIPIENT']
if sender == nil || rcpt == nil then
STDERR.puts "$SENDER and $RECIPIENT not set. exit."
exit 0 # メイル用プログラムはエラーでも exit 0 すべき
elsif /.*@.*/ !~ sender then # メイルアドレス形式でない場合
STDERR.puts "SENDER address invalid"
exit 0
end
to = sender
from = rcpt
subject = NKF.nkf("-M", 'メイル受信しました')
header = sprintf("To: %s\nFrom: %s\nSubject: %s\n\n", to, from, subject)
message = NKF.nkf("-j", "ありがとう\n")
program = sprintf("| sendmail -f %s %s", from, to)
open(program, "w") do |mail|
mail.print header
mail.print message
end
メイル配送により起動するプログラムはエラーで停止してはならない。 デバッグする際はメイル送信時と同じ状況を作り出してプログラムを起動する。 このスクリプトの例では,
SENDER と RECIPIENT に
値をセットする
の2点を満たしつつプログラムを起動する。適当なメイル格納ファイルが
~/Mail/inbox/1 にあったとすると,
cat ~/Mail/inbox/1 | \
SENDER=自分のメイルアドレス RECIPIENT=スクリプトの受信アドレス \
./pf3/thankyou.rb
のようにして確認する。問題がなければ,実際に電子メイル経由で 起動してみる。
echo test|Mail -s test-mail スクリプトの受信アドレス