プログラムによるメイル受信

電子メイルはそのメッセージがファイルとして保存されるだけではなく, メッセージの内容を標準入力としたプログラムの起動も行なえる。

qmailのプログラム配送

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個目のハイフン以降
DEFAULTdefault でマッチした文字列

上記の変数をうまく利用すればメイル処理プログラムが効率的に作れる。 簡単な例として,送信者に「ありがとう」とだけ返すプログラムを作る。

メイルアドレスは 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付の日本語メッセージを送る簡単な プログラムは以下のようになる。

sendjpex.rb

#!/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 から 取得し,そこにメイルを返すようにするのが簡単である。

プログラムは

という流れで作成する。

環境変数は,Rubyの変数 ENV にハッシュとして 入っている。たとえば,ENV["FOO"] は,環境変数 FOO が定義されている場合はその値が,定義されていない場合は nil が返る。

thankyou.rb

#!/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

メイル配送により起動するプログラムはエラーで停止してはならない。 デバッグする際はメイル送信時と同じ状況を作り出してプログラムを起動する。 このスクリプトの例では,

の2点を満たしつつプログラムを起動する。適当なメイル格納ファイルが ~/Mail/inbox/1 にあったとすると,

cat ~/Mail/inbox/1 | \
  SENDER=自分のメイルアドレス RECIPIENT=スクリプトの受信アドレス \
  ./pf3/thankyou.rb

のようにして確認する。問題がなければ,実際に電子メイル経由で 起動してみる。

echo test|Mail -s test-mail スクリプトの受信アドレス

本日の目次

yuuji@e.koeki-u.ac.jp