とあるサーバのテストで大量のダミーメールを一気に送信する必要が出た。大量と言ってもたかだか千通程度なので、簡単にシェルスクリプトを書いて送信。
表題には "Test Mail 1/1024 Mon Apr 10 12:58:19 JST 2006" などという文字列が、本文には日付だけがセットされる。Perl で書いても良かったけど、このマシンには SMTP 系のモジュール入れてたかどうかわからなかったのでシェルスクリプトにした。mail コマンドを使ってるので、ローカルで sendmail などの MTA が動いている必要がある。
・・・あれ? こういうローカルのプログラムからのメール配送要求を受け付けるプログラムも MTA (Mail Transfer Agent) でいいんだっけ? MDA (Mail Delivery Agent) または MUA (Mail User Agent) の方が適切? この場合の mail コマンドはメールをローカルで動いている MTA に渡すのが仕事なんだから、Mail User Agent が適切かな。
今気づいたけど、これはシェルスクリプトというかコマンドラインだね。
$ max=1024; date=`date`; for i in `seq 1 $max`; do echo $date |mail -s "Mail Test $i/$max $date" landscape@example.jp; done;
表題には "Test Mail 1/1024 Mon Apr 10 12:58:19 JST 2006" などという文字列が、本文には日付だけがセットされる。Perl で書いても良かったけど、このマシンには SMTP 系のモジュール入れてたかどうかわからなかったのでシェルスクリプトにした。mail コマンドを使ってるので、ローカルで sendmail などの MTA が動いている必要がある。
・・・あれ? こういうローカルのプログラムからのメール配送要求を受け付けるプログラムも MTA (Mail Transfer Agent) でいいんだっけ? MDA (Mail Delivery Agent) または MUA (Mail User Agent) の方が適切? この場合の mail コマンドはメールをローカルで動いている MTA に渡すのが仕事なんだから、Mail User Agent が適切かな。
今気づいたけど、これはシェルスクリプトというかコマンドラインだね。
Gmail でスパムが振り分けられて格納されるディレクトリに一通もスパムがないと Hooray, no spam here! って言われる。
スパムも含めて大量のメールがディレクトリに存在している方が、大容量のメールボックスとスパムフィルタ搭載を謳う Gmail らしさがある。でも、「スパムないよ!」 と無邪気に喜んでいる Gmail はなんだかほほえましい。私はこの表現が好きで、ついついスパムディレクトリを空にしてメッセージを見たくなる。
Hooray って応援団の「ふれー、ふれー!」の「ふれー」なのか。「オーライ!」のことかと思ったよ。
辞書を引くまで知らなかったけど、「ふれー」って「ばんざーい」って意味なんだね。
スパムも含めて大量のメールがディレクトリに存在している方が、大容量のメールボックスとスパムフィルタ搭載を謳う Gmail らしさがある。でも、「スパムないよ!」 と無邪気に喜んでいる Gmail はなんだかほほえましい。私はこの表現が好きで、ついついスパムディレクトリを空にしてメッセージを見たくなる。
Hooray って応援団の「ふれー、ふれー!」の「ふれー」なのか。「オーライ!」のことかと思ったよ。
辞書を引くまで知らなかったけど、「ふれー」って「ばんざーい」って意味なんだね。
Gmail のごみ箱ディレクトリである Trash ディレクトリのメールが30日経過で削除されるようになった。
いままでは messages that have been in Trash more than 30 days will be automatically deleted (30日経つと削除されます) と書かれていたが、なぜか実際には動作していなかった。2005-01-05 の「Gmail の Trash のメールが 30日経っても削除されない」で書いた。
私は 2004-11-09 の「GMail をバックアップストレージとして使う」などで Gmail を活用しているため、メールがあふれたりしていた。今日見たら使用している容量が一気に減っていた。もしかしてと思って Trash ディレクトリを見たら、ちょうど一ヶ月を境にメールが全部消えていた。よかったー。
ちなみに容量表示。
なんか不吉な数字だけどまあいいや。
いままでは messages that have been in Trash more than 30 days will be automatically deleted (30日経つと削除されます) と書かれていたが、なぜか実際には動作していなかった。2005-01-05 の「Gmail の Trash のメールが 30日経っても削除されない」で書いた。
私は 2004-11-09 の「GMail をバックアップストレージとして使う」などで Gmail を活用しているため、メールがあふれたりしていた。今日見たら使用している容量が一気に減っていた。もしかしてと思って Trash ディレクトリを見たら、ちょうど一ヶ月を境にメールが全部消えていた。よかったー。
ちなみに容量表示。
You are currently using 666 MB (25%) of your 2674 MB.
なんか不吉な数字だけどまあいいや。
友達に「http://sonic64.com/img/mail.png の画像ってどうやって作ったの?」と聞かれた。どこかの画像生成サービスで作ったということは覚えてるんだけど、サービスの URL がわからない。「ウェブ全体から検索」に切り替えたうえで、Google で Gmail Icon を検索するとヒット。
E-Mail Icon Generator
http://services.nexodyne.com/email/
このページだったかなあ? 違うような気もするけど、とりあえず生成してくれる画像は想像通りなので、たぶんここだろう。
E-Mail Icon Generator は多数のメールサービスに対応していて、それぞれのサービスの意匠を反映した画像を作ってくれる。こんな感じ。
Gmail
http://services.nexodyne.com/email/icon/b6N0IZUe0MU%3D/ZRw7P ...
Yahoo.co.jp
http://services.nexodyne.com/email/icon/JxajfHjVQRk%3D/hklZ% ...
Hotmail
http://services.nexodyne.com/email/icon/gSwcZ9PsmoM%3D/6vmnU ...
現時点で対応しているサービスは以下の通り。
AOL
ATT
Bigfoot
Blueyonder
Comcast
Cox
Earthlink
GMail
Hotmail
Lycos
MSN
Mac
Netscape
QQ
Rocket
Rogers
SBC
Sina
Spymac
Sympatico
VIPSina
Verizon
Yahoo
とくに、画像を自分のサイトにアップロードせずに生成サービスの URL を直接参照して画像を表示させるようにしていると、アドレス収集者に「この画像はメールアドレス画像」というヒントを与えてしまうことになり、より危険性が増すだろう。それを防ぐためには、自分の管理しているドメインや無料ホームページスペースに、メールアドレス画像と類推されないようなファイル名を付けてアップロードするのがよい。前述のメールアドレス画像のサンプルへのリンクなどは危険だ。たとえば、Gmail のメールアドレス画像 URL http://services.nexodyne.com/email/icon/b6N0IZUe0MU%3D/ZRw7P ... なら %3D/R01haWw%3D/0 という文字列が入るようだし。
なんか過敏になってるような気もするが、そのくらい用心しないとスパムは減らない。
E-Mail Icon Generator
http://services.nexodyne.com/email/
このページだったかなあ? 違うような気もするけど、とりあえず生成してくれる画像は想像通りなので、たぶんここだろう。
E-Mail Icon Generator は多数のメールサービスに対応していて、それぞれのサービスの意匠を反映した画像を作ってくれる。こんな感じ。
Gmail
http://services.nexodyne.com/email/icon/b6N0IZUe0MU%3D/ZRw7P ...
Yahoo.co.jp
http://services.nexodyne.com/email/icon/JxajfHjVQRk%3D/hklZ% ...
Hotmail
http://services.nexodyne.com/email/icon/gSwcZ9PsmoM%3D/6vmnU ...
現時点で対応しているサービスは以下の通り。
AOL
ATT
Bigfoot
Blueyonder
Comcast
Cox
Earthlink
GMail
Hotmail
Lycos
MSN
Mac
Netscape
Rocket
Rogers
SBC
Sina
Spymac
Sympatico
VIPSina
Verizon
Yahoo
- みんなが同じ画像生成サービスを使うと、スパム業者に画像解析されちゃうのでは?
メールアドレスをテキストではなく画像にする理由の一つは、スパム業者やワームにアドレスを収集されないようにするため。でも、みんながみんな同じメールアドレス画像生成サービスを使っていると、画像のパターンからアドレス文字列を解析されてしまうかもしれない。とくに、画像を自分のサイトにアップロードせずに生成サービスの URL を直接参照して画像を表示させるようにしていると、アドレス収集者に「この画像はメールアドレス画像」というヒントを与えてしまうことになり、より危険性が増すだろう。それを防ぐためには、自分の管理しているドメインや無料ホームページスペースに、メールアドレス画像と類推されないようなファイル名を付けてアップロードするのがよい。前述のメールアドレス画像のサンプルへのリンクなどは危険だ。たとえば、Gmail のメールアドレス画像 URL http://services.nexodyne.com/email/icon/b6N0IZUe0MU%3D/ZRw7P ... なら %3D/R01haWw%3D/0 という文字列が入るようだし。
なんか過敏になってるような気もするが、そのくらい用心しないとスパムは減らない。
最近、ブログや掲示板にコメントを投稿するとき、メールアドレス欄には http://sonic64.com/img/mail.png と書くようにしている。
2ちゃんねるだったら、メール欄は sage って書いたり空欄なのが普通なのでそれでいい。あれはメールアドレスを書く欄として使ってる人はまずいない。
一般の掲示板や blog だと、コメント時のメールアドレスは入力必須にしてるところもある。そういうときは example@example.com って書いてた。でも、それもなんだか相手に失礼。捨てアドレスでもいいが、そうすると返信されてもまったく気づかない。
なので、最近は http://sonic64.com/img/mail.png って書くようにしている。要するに、メールアドレスを書いた画像ファイル の URL。これならスパムに使われる可能性は文字に比べて激減するし、人間には読める。blog や掲示板管理者はダミーでない連絡先を知ることができ、私はあまり後ろめたい気持ちを持たずにメールアドレス欄に入力できる。
あ、でも気合いの入ったスパム業者だと、有名なメールアドレス画像生成サービスの生成した画像くらいは解析できるようにしてそうだ。しかも、メールアドレス欄に書いちゃうとメールアドレス画像ってことを明示してるようなものなので、より解析される危険性が高まりそうだ。まあ、そうしたらスパムフィルタ使えばいいか。とにかく、機械解析のハードルを高くすることが重要だからね。
- スパムはイヤ
ブログや掲示板のメールアドレス欄。そのまま自分のメールアドレスを書くと、スパム業者のロボットにアドレスを収集されてスパムメールがわんさか来るようになるので、そのままでは書きたくない。コメントやお礼は書きたい。でもスパムに悩まされたくはない。スパムフィルタを使うのもいいけど、そもそもスパムが来ない方が良い。2ちゃんねるだったら、メール欄は sage って書いたり空欄なのが普通なのでそれでいい。あれはメールアドレスを書く欄として使ってる人はまずいない。
一般の掲示板や blog だと、コメント時のメールアドレスは入力必須にしてるところもある。そういうときは example@example.com って書いてた。でも、それもなんだか相手に失礼。捨てアドレスでもいいが、そうすると返信されてもまったく気づかない。
なので、最近は http://sonic64.com/img/mail.png って書くようにしている。要するに、メールアドレスを書いた画像ファイル の URL。これならスパムに使われる可能性は文字に比べて激減するし、人間には読める。blog や掲示板管理者はダミーでない連絡先を知ることができ、私はあまり後ろめたい気持ちを持たずにメールアドレス欄に入力できる。
あ、でも気合いの入ったスパム業者だと、有名なメールアドレス画像生成サービスの生成した画像くらいは解析できるようにしてそうだ。しかも、メールアドレス欄に書いちゃうとメールアドレス画像ってことを明示してるようなものなので、より解析される危険性が高まりそうだ。まあ、そうしたらスパムフィルタ使えばいいか。とにかく、機械解析のハードルを高くすることが重要だからね。
- 当サイト Landscape もコメント欄付けよう
やっぱりコメント欄あった方がすぐにツッコミや指摘ができて便利だ。そのうち付けよう。RFC2046 には External-Body という形式がある。添付ファイルを別の場所に分離して保存する方法を規定したものだ。
自分でそういったフォーマットを作っても良いけど、可能な限り標準に準拠した形式にしておきたい。確か、私のやりたいことに適合した MIME タイプがあったはず。探してみよう。
rfc2046(jp) Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types メディアタイプ
http://www.asahi-net.or.jp/~bd9y-ktu/dtd_f/rfc_f/rfc2046j.ht ...
あった。RFC 2046 の 5.2.3. 外部ボディ(External-Body)サブタイプだ。これを使えばいいのか。
RFC2046にはオリジナルのファイル名を記述するフィールドを規定していないようだ。そこで、X-Original-File-Name というヘッダを付け、Base64 でエンコードしたオリジナルのファイル名を記述するようにした。
Content-Type の name は相対パスで記述。良くないかもしれないけど。あと、システムは Windows なのでディレクトリ区切り文字は \ を使った。これも微妙かも。
このようにして、attachment\00080386.dat に添付ファイルのデータを保存していることを表現できる。
- RFC2046の External-Body
とあるプログラムを作成中。このプログラムは、データを MIME 互換形式で保存する。データには添付ファイルのようなものも含まれる。個数は可変。MIME の multipart/mixed を使えば添付ファイルのデータをメインのデータに含めることができるが、それはしたくない。添付ファイルのデータは別のファイルに保存したい。自分でそういったフォーマットを作っても良いけど、可能な限り標準に準拠した形式にしておきたい。確か、私のやりたいことに適合した MIME タイプがあったはず。探してみよう。
rfc2046(jp) Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types メディアタイプ
http://www.asahi-net.or.jp/~bd9y-ktu/dtd_f/rfc_f/rfc2046j.ht ...
あった。RFC 2046 の 5.2.3. 外部ボディ(External-Body)サブタイプだ。これを使えばいいのか。
- RFC2046の External-Body のサンプル
RFC2046を読みながらサンプルを書いた。Content-Type が二回出てくるのが新鮮な感じ。RFC2046にはオリジナルのファイル名を記述するフィールドを規定していないようだ。そこで、X-Original-File-Name というヘッダを付け、Base64 でエンコードしたオリジナルのファイル名を記述するようにした。
Content-Type の name は相対パスで記述。良くないかもしれないけど。あと、システムは Windows なのでディレクトリ区切り文字は \ を使った。これも微妙かも。
--------------050807090903030402050103
Content-Type: message/external-body;
access-type=local-file;
name="attachment\00080386.dat";
size=80386
Content-Type: application/octet-stream
Content-ID: BAa2YGktNCKZnJlLHg0NKlpaU9ov
X-Original-File-Name: Base64_ENCODED_FILE_NAME
--------------050807090903030402050103
このようにして、attachment\00080386.dat に添付ファイルのデータを保存していることを表現できる。
タスクマネージャを見ていたら POP3Trap.exe という名前のプログラムが動いている。私には心当たりがない。もしかしてウイルスやスパイウェアか? とドキドキしながら Google で POP3Trap.exe を検索するとヒット。
POP3Trap.exe はウイルスバスターが起動するプロセスだそうだ。POP3 の通信を検疫するため、ローカルに POP3 プロキシを立てて通信を中継している模様。最初は気味が悪いと思ったけど、まあウイルスチェックのためだし仕方ないかな。
Outlook Express だと勝手に POP サーバの設定エントリを localhost に書き換えて POP3Trap を経由するように設定するとのこと。Mozilla Thunderbird だと今のところそういった設定に書き換えられることは無いみたいだけど。
POP3Trap.exe はウイルスバスターが起動するプロセスだそうだ。POP3 の通信を検疫するため、ローカルに POP3 プロキシを立てて通信を中継している模様。最初は気味が悪いと思ったけど、まあウイルスチェックのためだし仕方ないかな。
Outlook Express だと勝手に POP サーバの設定エントリを localhost に書き換えて POP3Trap を経由するように設定するとのこと。Mozilla Thunderbird だと今のところそういった設定に書き換えられることは無いみたいだけど。
C# で MUA (Mail User Agent) を作っていて、文書の保存フォーマットを検討している。それぞれの形式についてメモ。
複数のメールを一ファイルにまとめるため、メールを区切る区切り文字が必要。以下のように From ENVELOPE_FROM DATETIME_STRING を使う。
本文中に上記文字列がある場合、> でエスケープされる。
一つ以上の > と それに続く From で始まる行にも > を付加する。そうしないと可逆にならない。mbox 形式はこのエスケープとアンエスケープの仕様にいくつかの流派があるようで、互換性やデータの可逆性を損なっている。
可逆なエスケープとアンエスケープを正規表現で書くと以下のようになるかな。
参考。
mbox(5)
http://man.qmail.jp/jman5/mbox.html
maildir(5)
http://www.qmail.org/qmail-manual-html/man5/maildir.html
日本語訳。
maildir(5)
http://man.qmail.jp/jman5/maildir.html
ユーザが自分でさらにサブディレクトリを作ったらどうなるんだろう? 特に問題ないような気もするけど、Maildir を扱う MUA は使ったことないのでよくわからないな。
Outlook Express dbx file format by Arne Schloh
http://oedbx.aroh.de/
- mbox 形式
一般的かつ伝統的。複数の文書を一ファイルに連結して扱う。Mozilla Thunderbird や Unix 系の MTA/MUA の多くでサポートされている。複数のメールを一ファイルにまとめるため、メールを区切る区切り文字が必要。以下のように From ENVELOPE_FROM DATETIME_STRING を使う。
From example@example.com Thu Jul 14 14:35:40 2005
本文中に上記文字列がある場合、> でエスケープされる。
>From example@example.com Thu Jul 14 14:35:40 2005
一つ以上の > と それに続く From で始まる行にも > を付加する。そうしないと可逆にならない。mbox 形式はこのエスケープとアンエスケープの仕様にいくつかの流派があるようで、互換性やデータの可逆性を損なっている。
可逆なエスケープとアンエスケープを正規表現で書くと以下のようになるかな。
# mbox > エスケープ
s/^(>*)From /$1>From /
# mbox > アンエスケープ
s/^>(>*From )/$1/
参考。
mbox(5)
http://man.qmail.jp/jman5/mbox.html
- MH 形式
一メール一ファイルで構成する。仕様はどこにあるんだろう? mh 配布アーカイブ内かな?- Maildir 形式
qmail で使える形式。MTA じゃなくて MUA でも使うメリットはあるけど、シングルユーザーを前提とした MUA 環境ではオーバースペックな気がする。優れた形式だとは思うけど。maildir(5)
http://www.qmail.org/qmail-manual-html/man5/maildir.html
日本語訳。
maildir(5)
http://man.qmail.jp/jman5/maildir.html
ユーザが自分でさらにサブディレクトリを作ったらどうなるんだろう? 特に問題ないような気もするけど、Maildir を扱う MUA は使ったことないのでよくわからないな。
- Outlook Express の dbx 形式
dbx という拡張子。中身はバイナリ。インデックスファイルなし。このフォーマットって公開されてるんだろうか? 調べても MS のサイトがヒットしない。リバースエンジニアリングして公開してる人がいるくらいかな。Mozilla Thunderbird のソースとかも参考になりそう。Outlook Express dbx file format by Arne Schloh
http://oedbx.aroh.de/
- RDBMS を使う
フォーマットを考えたりアクセス用のファサードクラスを実装するのが面倒なら、DB を使ってメールを格納してしまうのが手っ取り早い。たぶんこの方法はやらないけど。Windows なら MSDE など。ライブラリがあってライセンス的に問題がなければ QDBM とか BerkeleyDB なども候補になる。手元に eml ファイルが50個ほどある。これを愛用のメールクライアントである Mozilla Thunderbird にインポートしたい。
当該 eml ファイルは、Outlook Express で受信したメールをエクスポートしたもの。
しかしながら、今回は直接 Mozilla Thunderbird にインポートする方法を見つけられなかったので、一度 Outlook Express にインポートしてから Thunderbird にインポートする手順を踏む。
Outlook Express 6 を起動し、受信トレイを開く。
右上のメール一覧ペインに該当ファイルを全部ドラッグ & ドロップすると、Outlook Express にインポートできる。
Mozilla Thunderbird 1.0.2 を起動し、上部メニューの ツール(T) の インポート(I) を選択。
インポートする内容の選択で「メールボックス」を選択。
インポート元のプログラムの選択で「Outlook Express」を選択。
Mozilla Thunderbird の「ローカルフォルダ」にインポートしたメールが生成される。
当該 eml ファイルは、Outlook Express で受信したメールをエクスポートしたもの。
- 一度 Outlook Express にインポートしてから、Thunderbird にインポートする
eml ファイルはテキストファイルなので、いろいろと方法はあると思う。専用のツールがあるかもしれないし、eml インポートのためのインターフェイスが Mozilla Thunderbird に用意されているかもしれない。しかしながら、今回は直接 Mozilla Thunderbird にインポートする方法を見つけられなかったので、一度 Outlook Express にインポートしてから Thunderbird にインポートする手順を踏む。
Outlook Express 6 を起動し、受信トレイを開く。
右上のメール一覧ペインに該当ファイルを全部ドラッグ & ドロップすると、Outlook Express にインポートできる。
Mozilla Thunderbird 1.0.2 を起動し、上部メニューの ツール(T) の インポート(I) を選択。
インポートする内容の選択で「メールボックス」を選択。
インポート元のプログラムの選択で「Outlook Express」を選択。
Mozilla Thunderbird の「ローカルフォルダ」にインポートしたメールが生成される。
2005-05-13 の「Bloglines で本文が表示されない現象の原因と対処」で書いた現象を Bloglines に報告した。現象は、channel 要素内の title 要素にマルチバイト文字列を使っていて、かつタイトルの長さが長い場合、 本文が表示されないというもの。
もっとも、日本語でも英語でもバグレポートの基本は一緒だよね。
発生した現象
期待する動作
再現手順や環境
この3つを書けばいいだけ。
以下を読んだけど、それらしき物はない。FAQ ってどこかにあったような気もするけど、どこだっけ?
Bloglines | Bloglinesからお知らせ
http://www.bloglines.com/about/news
送信先について。専用のメールアドレスがあるわけではなく、以下のフォームから送ればいい。前送ったときもそうだったっけ。すっかり忘れちゃってる。
Bloglines | お問い合わせ
http://www.bloglines.com/contact
・・・って、フォームもお問い合わせページも日本語で書いてあるんだけど、バグ報告も日本語でいいの? せっかく 英語で書かなきゃ! と気合い入れたのにね。前は英語のページしかなかったから英語で書いたんだけど。
あ、「よくある質問」があった。よくある質問 http://www.bloglines.com/help/faq の中には本バグレポートの現象は載ってないね。よし、書くぞ。
http://sonic64.com/2005-05-13.html
上記のウェブページに書いたから読んでね、というだけのレポートでも良いのかもしれないけど、もらった方としてはそれでは処理に困るかもしれない。もしかしたらフォームから送信した文面は自動翻訳されて開発チームに届くかもしれないし、BTS (Bug Tracking System - バグ追跡システム) にそのまま掲載されるかもしれないし。そもそも、「質問は以下のウェブサイトに書きました」とか「質問は添付ファイルの通りです」といったメールって、もらう立場から考えると嬉しい物じゃないし。メール本文に書いてくれればいいのに、って思っちゃう。
というわけで、本文に全部盛り込むようにし、以下をフォームから送信した。
フォームから送ると以下のメッセージが表示された。
送信完了。
- 英語でバグレポート
私は英語嫌いじゃないけど、普段使ってないからうまく書けないんだよなあ。時間もかかるし。2005-01-09 の「favicon.ico が bloglines で表示されない理由」で書いたバグレポートを送ったときもちょっと大変だった。もっとも、日本語でも英語でもバグレポートの基本は一緒だよね。
発生した現象
期待する動作
再現手順や環境
この3つを書けばいいだけ。
- 既知の問題かどうかと、バグレポートの送り先を確認する
さて、まず同様のレポートが既に提出されているかどうかと、送り先を確認する。以下を読んだけど、それらしき物はない。FAQ ってどこかにあったような気もするけど、どこだっけ?
Bloglines | Bloglinesからお知らせ
http://www.bloglines.com/about/news
送信先について。専用のメールアドレスがあるわけではなく、以下のフォームから送ればいい。前送ったときもそうだったっけ。すっかり忘れちゃってる。
Bloglines | お問い合わせ
http://www.bloglines.com/contact
・・・って、フォームもお問い合わせページも日本語で書いてあるんだけど、バグ報告も日本語でいいの? せっかく 英語で書かなきゃ! と気合い入れたのにね。前は英語のページしかなかったから英語で書いたんだけど。
あ、「よくある質問」があった。よくある質問 http://www.bloglines.com/help/faq の中には本バグレポートの現象は載ってないね。よし、書くぞ。
- Bloglines に送ったバグ報告メール
Bloglines で本文が表示されない現象の原因と対処http://sonic64.com/2005-05-13.html
上記のウェブページに書いたから読んでね、というだけのレポートでも良いのかもしれないけど、もらった方としてはそれでは処理に困るかもしれない。もしかしたらフォームから送信した文面は自動翻訳されて開発チームに届くかもしれないし、BTS (Bug Tracking System - バグ追跡システム) にそのまま掲載されるかもしれないし。そもそも、「質問は以下のウェブサイトに書きました」とか「質問は添付ファイルの通りです」といったメールって、もらう立場から考えると嬉しい物じゃないし。メール本文に書いてくれればいいのに、って思っちゃう。
というわけで、本文に全部盛り込むようにし、以下をフォームから送信した。
長いマルチバイト文字列をタイトルに使った RSS だと本文が表示されません。
Bloglines の MyFeed でフィードを閲覧しようとすると、フィードのタイトルだけ表示されて本文が表示されないという現象が発生します。この現象について調査した結果を私のウェブサイトに載せています。
Bloglines で本文が表示されない現象の原因と対処
http://sonic64.hp.infoseek.co.jp/2005-05-13.html
以下に要約を書きます。
http://sonic64.hp.infoseek.co.jp/test/index.rdf の RSS を Bloglines で表示させると、タイトルのみ表示され、本文が表示されません。http://www.bloglines.com/preview?siteid=1840248 が問題のあるプレビューです。
RSS の Item 要素には Description と content:encoded が含まれています。通常であれば、フィードの item が表示されるはずですが、フィードのタイトルしか表示されません。ただし、この現象が発生するのは Internet Explorer を使ったときで、Firefox を使うとこの現象は発生しませんでした。
使用している Ineternet Explorer と Firefox のバージョンは以下の通りです。
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)
Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.7) Gecko/20050414 Firefox/1.0.3
http://sonic64.hp.infoseek.co.jp/test/index.rdf の RSS は channel 要素内の title 要素が非常に長いものとなっています。試しに channel 要素内の title 要素を短くした RSS を作って Bloglines で表示させてみると、Internet Explorer でも Firefox でも問題なく表示されました。
channel 要素内の title 要素を短くした RSS と、Bloglines におけるプレビュー
http://sonic64.hp.infoseek.co.jp/test/index_short.rdf
http://www.bloglines.com/preview?siteid=1840267
以下は私の推測です。
channel 要素内の title 要素が非常に長く、かつ日本語などのマルチバイトを必要とする文字コードで記述されていた場合、バイト境界を無視して文字を途中で切断してしまうようです。この結果、Bloglines が出力する HTML に文字化けが発生し、本文が表示されなくなってしまうのではないでしょうか。
フォームから送ると以下のメッセージが表示された。
あなたのメッセージは Bloglinesに送信されました。Bloglinesがメッセージを拝見させて頂くのには、2営業日はお待ち頂く必要があります。
送信完了。
Gmail の Trash ディレクトリに移動したメールは30日経つと自動削除されるはずだが、どうやら動いていないようだ。
なんでこんなことになってるのか。もしかして古いバックアップが削除されていないのでは? とおもって Trash を見ると、バックアップメールがたくさん残っていた。一番古い物は2004年10月26日のものだ。
仕様変更ってわけでもないよね。以下のようにちゃんと書いてあるし。なんでだろう?
Google さん、お願いだから Trash に入れて30日経ったメールは削除してください。手作業で削除するのは手間だし、忘れちゃう。
「1000MB もストレージがあるなら、削除する必要なんてある?」というメッセージ。いや、私は削除が必要だったんだけど・・・。1テラバイトくらいディスクスペースをくれるなら削除する必要はないと思うけどね。
- Gmail は手頃なネットワーク上のストレージ
2004-11-09 の「GMail をバックアップストレージとして使う」で書いたが、私はバックアップファイルを暗号化し添付ファイルとして Gmail に送信するスクリプトを定期的に動かしている。このバックアップメールは Gmail に届くと自動的に Trash ディレクトリに移動されるようにフィルタを設定してある。Trash に入ったメールは30日経過すると自動的に削除されるので手間がかからない。- 1GB の Gmail メールボックスが溢れた
Gmail にログインしてみると、以下のようなメッセージが表示されていた。どうやらメールボックスがいっぱいになってしまったらしい。容量表示メッセージはいつもは緑色なのだが、以下は赤い色だった。You are currently using 1003 MB (100%) of your 1000 MB.
なんでこんなことになってるのか。もしかして古いバックアップが削除されていないのでは? とおもって Trash を見ると、バックアップメールがたくさん残っていた。一番古い物は2004年10月26日のものだ。
- せっせ、せっせと削除
なんで30日経ったメールが残ってるんだろう? 仕方がないので手作業で削除。Select: All を選択して、Delete Forever ボタンを押す。Newer を押してページを切り替え、同じことを繰り返す。10回ほど繰り返したら700MB ほど空き容量ができた。仕様変更ってわけでもないよね。以下のようにちゃんと書いてあるし。なんでだろう?
Note: Trashed messages more than 30 days old will be automatically deleted.
Google さん、お願いだから Trash に入れて30日経ったメールは削除してください。手作業で削除するのは手間だし、忘れちゃう。
- Gmail が表示した気になるメッセージ
削除を実行してそのページ中に一つもメールが無くなったとき、以下のメッセージが表示された。ちょっと気になるな。No conversations in the trash. Who needs to delete when you have 1000 MB of storage?!
「1000MB もストレージがあるなら、削除する必要なんてある?」というメッセージ。いや、私は削除が必要だったんだけど・・・。1テラバイトくらいディスクスペースをくれるなら削除する必要はないと思うけどね。
* GMail をバックアップストレージとして使う
この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [Google] [メール] [シェルスクリプト] [バックアップ] [gpg]
GMail の 1GB という容量を生かして、バックアップストレージとして使う方法。
ストレージというと大げさな感じがするが、やってることは暗号化したアーカイブファイルを GMail にメール送信するスクリプトを書き、これを cron で一時間ごとに実行するだけ。GmailFS などを使ってファイルシステムとしてマウントするのも一つの方法だとは思うが、バックアップなんだから安定性重視でいきたいし、こういうのはシンプルな方がいい。
今日の戯言 ChangeLog 主にテキストファイルを gmail にバックアップ
http://apollo.u-gakugei.ac.jp/~sunaoka/clog/2004-11.php#2004 ...
1GB の容量を与えられたらそれを活用しようとする人はたくさんいるし、実装もたくさんあるようなので確かに車輪の再発明かもしれないですね。でも、自分好みの機能やインターフェイスにしたいなら、スクリプトを書いちゃう方が良いと思います。File::MMagic と Compress::Zlib を使って、テキストだったら圧縮するという機能は面白いと思いましたし。
送信先は GMail をはじめとするメールボックス容量に余裕のあるアドレス。メールなので数十メガバイトのファイルのバックアップという用途には適さない。ChangeLog メモのファイルや自分用 CVS リポジトリ、etc ディレクトリなど、小さなものだけをバックアップしている。Gmail のアカウントを取得する前は一日一回だったが、Gmail ができてからは一時間に一回に実行頻度を上げた。
内容にもよるが、外部にデータを持ち出すなら暗号化は必須だと感じている。GnuPG を使えばフリーで強力な暗号を利用可能。具体的には 2004-01-08 で書いた「gpg で標準入力からパスワードを渡してバッチ処理で暗号化」を利用し、GPG の共通鍵暗号で暗号化している。
暗号化アルゴリズムには AES256 (256bit Advanced Encryption Standard) を指定。gpg のデフォルトの CAST5 でも良いと思うけど、AES は NIST (National Institute of Standards and Technology 米国商務省技術標準局) 御用達の暗号化アルゴリズムとのことなので、これを使うことにした。
Perl だったら Crypt::CAST5 や Crypt::Rijndael とか使うのが一般的なのかな?
以前は暗号化した圧縮ファイルの md5 ハッシュを取っておいて、前回と異なったときのみメール送信という動きにしていたが、その機能は外してしまった。そういう意味では一度ファイル出力せずに直接 samail の標準入力に渡した方がシンプルだな。よし、samail の次のバージョンでは標準入力から読み込んだデータを添付ファイルとして送信できるようにしよう。
PASS_PHRASE に gpg に渡すパスフレーズ、TAR_TARGET にバックアップしたいファイルやディレクトリのパス、OUTPUT_PATH に暗号化した圧縮ファイルの出力先を記述。あとは To と From と SMTP サーバ名を書いて完了。Ruby のパスを /usr/local/bin/ruby と samail のパスを /home/hiroaki/script/samail とハードコーディングしてるのはあまり良くないかも。
私の場合 cygwin ネイティブのファイルシステムと /cygdrive の両方にバックアップしたいファイルがあるため、/ からフルパスで TAR_TARGET を記述している。このせいで tar に以下のようなメッセージを表示されるけど、実害がないので問題ないだろう。
メール送信時に Subject に特徴的な文字列を入れておき、その文字列でフィルタリング。マッチしたメールは自動的に Trash 行きになるように設定する。こうすることで「30日を過ぎたバックアップファイルは自動的に削除」を実現できる。
一回 1MB のファイルを送るとして、1MB * 24時間 * 30日 = 720MB 、Base64 すると 3分の4倍くらいになるので、それを含めても 1MB * 24時間 * 30日 * 4 / 3 = 960MB。24時間稼働のマシンでなければ頻度はもっと減るし、一日一回にしておけばさらに余裕。ところで、GMail って添付ファイルは Base64 デコードした状態でファイルサイズを計算している気がするんだけど気のせいかな。
--force-mdc オプションなしで暗号化したファイルの場合、以下のメッセージが表示されるかも知れない。これについては私も詳しくないので言及しない。とりあえず --force-mdc を付ければ警告は出なくなる。
bzip2 の警告は、末尾になにか余計なデータがあるので無視するよ、というもの。理由は不明。tar の出力を直接 gpg の標準入力に渡しているから?
ITmediaニュース:GmailがPOP3サポート、ウイルス対策も提供へ
http://www.itmedia.co.jp/news/articles/0411/11/news010.html
これでさらにストレージとして利用するのが簡単になった。そのうち 読み書き用の API を書く人も出てくるだろうな。POP/SMTP ベースだと遅延があるのでリアルタイム性を要求するアプリケーションには使えないだろうけど、用途を選べば充分使える。
ストレージというと大げさな感じがするが、やってることは暗号化したアーカイブファイルを GMail にメール送信するスクリプトを書き、これを cron で一時間ごとに実行するだけ。GmailFS などを使ってファイルシステムとしてマウントするのも一つの方法だとは思うが、バックアップなんだから安定性重視でいきたいし、こういうのはシンプルな方がいい。
今日の戯言 ChangeLog 主にテキストファイルを gmail にバックアップ
http://apollo.u-gakugei.ac.jp/~sunaoka/clog/2004-11.php#2004 ...
主にテキストファイルを gmail にバックアップするつもりででっち上げてみたが,車輪の再開発のような気がしてならない.
1GB の容量を与えられたらそれを活用しようとする人はたくさんいるし、実装もたくさんあるようなので確かに車輪の再発明かもしれないですね。でも、自分好みの機能やインターフェイスにしたいなら、スクリプトを書いちゃう方が良いと思います。File::MMagic と Compress::Zlib を使って、テキストだったら圧縮するという機能は面白いと思いましたし。
- GMail をバックアップストレージとして使う - 私の場合
私の場合、シェルスクリプトで tar と gpg を呼び出して圧縮と暗号化をおこない、2004-10-09 と 2004-11-01 で書いた「添付ファイル付メールを送信する Ruby スクリプト」である samail で SMTP サーバに投げている。送信先は GMail をはじめとするメールボックス容量に余裕のあるアドレス。メールなので数十メガバイトのファイルのバックアップという用途には適さない。ChangeLog メモのファイルや自分用 CVS リポジトリ、etc ディレクトリなど、小さなものだけをバックアップしている。Gmail のアカウントを取得する前は一日一回だったが、Gmail ができてからは一時間に一回に実行頻度を上げた。
内容にもよるが、外部にデータを持ち出すなら暗号化は必須だと感じている。GnuPG を使えばフリーで強力な暗号を利用可能。具体的には 2004-01-08 で書いた「gpg で標準入力からパスワードを渡してバッチ処理で暗号化」を利用し、GPG の共通鍵暗号で暗号化している。
暗号化アルゴリズムには AES256 (256bit Advanced Encryption Standard) を指定。gpg のデフォルトの CAST5 でも良いと思うけど、AES は NIST (National Institute of Standards and Technology 米国商務省技術標準局) 御用達の暗号化アルゴリズムとのことなので、これを使うことにした。
Perl だったら Crypt::CAST5 や Crypt::Rijndael とか使うのが一般的なのかな?
#!/bin/sh
# gmail_backup.sh
# Archiving, Crypting, and mail sending script
# Copyright (C) 2004 Saito Hiroaki <sonic64@infoseek.jp>
# http://sonic64.com/
# setup
PASS_PHRASE="MY SECRET PASS PHRASE STRING"
TAR_TARGET="/home/hiroaki/log.txt /home/hiroaki/etc /cygdrive/s/cvsroot"
OUTPUT_PATH="/home/hiroaki/tmp/backup.tar.bz2.encoded"
to_address="to@example.com, to@gmail.example.com"
optional_adderss="to@daily.example.com"
from_address="from@example.com"
smtp_server="smtp.example.com"
date
echo $TAR_TARGET
echo $PASS_PHRASE | { tar --bzip2 -cf - $TAR_TARGET |gpg --batch -c --cipher-algo AES256 --force-mdc --passphrase-fd 3;} 3>&0 >$OUTPUT_PATH
echo output to $OUTPUT_PATH
echo archiving complete
if [ `date +%H` -eq 23 ]; then
to_address="$to_address $optional_adderss"
fi
/usr/local/bin/ruby /home/hiroaki/script/samail -v --to "$to_address" --from $from_address --smtp $smtp_server --subject "[GMail Backup] `date +%c`" --attachment $OUTPUT_PATH
date
echo mail send complete
以前は暗号化した圧縮ファイルの md5 ハッシュを取っておいて、前回と異なったときのみメール送信という動きにしていたが、その機能は外してしまった。そういう意味では一度ファイル出力せずに直接 samail の標準入力に渡した方がシンプルだな。よし、samail の次のバージョンでは標準入力から読み込んだデータを添付ファイルとして送信できるようにしよう。
- gmail_backup.sh の設定方法
# setup のところに設定を書く。PASS_PHRASE に gpg に渡すパスフレーズ、TAR_TARGET にバックアップしたいファイルやディレクトリのパス、OUTPUT_PATH に暗号化した圧縮ファイルの出力先を記述。あとは To と From と SMTP サーバ名を書いて完了。Ruby のパスを /usr/local/bin/ruby と samail のパスを /home/hiroaki/script/samail とハードコーディングしてるのはあまり良くないかも。
私の場合 cygwin ネイティブのファイルシステムと /cygdrive の両方にバックアップしたいファイルがあるため、/ からフルパスで TAR_TARGET を記述している。このせいで tar に以下のようなメッセージを表示されるけど、実害がないので問題ないだろう。
tar: Removing leading `/' from member names
- GMail 側の設定
Gmail といえども 1GB しか容量がないので、古いバックアップファイルは削除する必要がある。Gmail の Trash ディレクトリは 30日過ぎると削除されるという性質があるので、これを利用する。この性質は Trash を開いたときに出るメッセージに書かれていた。Note: Trashed messages more than 30 days old will be automatically deleted.
メール送信時に Subject に特徴的な文字列を入れておき、その文字列でフィルタリング。マッチしたメールは自動的に Trash 行きになるように設定する。こうすることで「30日を過ぎたバックアップファイルは自動的に削除」を実現できる。
- メール送信の頻度はどれくらいがよいか
これはもうお好みで良いと思う。一日一回くらいでも充分なんじゃないかと思うが、せっかく容量があるんならいっぱい送っちゃえ、ということで一時間に一回にしている。一回 1MB のファイルを送るとして、1MB * 24時間 * 30日 = 720MB 、Base64 すると 3分の4倍くらいになるので、それを含めても 1MB * 24時間 * 30日 * 4 / 3 = 960MB。24時間稼働のマシンでなければ頻度はもっと減るし、一日一回にしておけばさらに余裕。ところで、GMail って添付ファイルは Base64 デコードした状態でファイルサイズを計算している気がするんだけど気のせいかな。
- 一日一回だけ別のアドレスを追加して送信
このスクリプトは cron で一時間ごとに起動しているが、23時台に起動したときだけ optional_adderss にセットされた送信先を追加している。Gmail ほどメールボックス容量に余裕がないアドレスなので、一日一回だけの送信にしたいからだ。Gmail の予備として使っている。if [ `date +%H` -eq 23 ]; then
to_address="$to_address $optional_adderss"
fi
- 分割すれば巨大ファイルでも OK?
分割すれば数十メガバイト単位の巨大ファイルでもバックアップできるが、いざリストアしようと思ったときに分割したメールを連結するという手間をかけたくない。標準で POP で受信できない場合はなおさら。そういう巨大ファイルは他の方法を使うべきでだ。どうしてもネットワーク経由でのバックアップがしたいなら、2004-03-19 で書いた「Linux: gpg: ftp: ftp + tar + gpgで暗号化ネットワーク・バックアップ」などが使えるかもしれない。- 正常に復号して圧縮ファイルを展開できるかどうかのテストを忘れずに
バックアップしただけで安心してはいけない。いざという時にに迅速にリストアできなければ意味がない。私は以下のようにして復号と圧縮ファイルの展開をしている。$ echo "MY SECRET PASS PHRASE STRING" |gpg --passphrase-fd 0 -o - backup.tar.bz2.encoded |tar -x --bzip2
Reading passphrase from file descriptor 0
gpg: AES256 encrypted data
gpg: encrypted with 1 passphrase
bzip2: (stdin): trailing garbage after EOF ignored
--force-mdc オプションなしで暗号化したファイルの場合、以下のメッセージが表示されるかも知れない。これについては私も詳しくないので言及しない。とりあえず --force-mdc を付ければ警告は出なくなる。
gpg: WARNING: message was not integrity protected
bzip2 の警告は、末尾になにか余計なデータがあるので無視するよ、というもの。理由は不明。tar の出力を直接 gpg の標準入力に渡しているから?
- 「フッフッフッフッフッフッ まぬけめ! Gmail」「や…やろう まさか!」「きさまのおかげで ストレージ利用がしやすくなったぞッ!」
追記。Gmail が POP3 をサポートするとのこと。ITmediaニュース:GmailがPOP3サポート、ウイルス対策も提供へ
http://www.itmedia.co.jp/news/articles/0411/11/news010.html
これでさらにストレージとして利用するのが簡単になった。そのうち 読み書き用の API を書く人も出てくるだろうな。POP/SMTP ベースだと遅延があるのでリアルタイム性を要求するアプリケーションには使えないだろうけど、用途を選べば充分使える。
ユーザーコマンド sendmail (1) で from を指定するには -f を使う。指定できる from は envelope from なので、ヘッダに from を入れたければ sedamail コマンドへの入力文字列中に From ヘッダを含めておかなければならない。
使用例。
SENDMAIL(1) sendmail - Postfix Sendmail 互換インターフェース
http://www.kobitosan.net/postfix/jman/sendmail.1.html
なぜか私の Linux マシンには sendmail(1) の man page がインストールされてなかった。sendmail(8) の man page はある。仕方がないので、postfix の sendmail コマンドの man pageを参照。sendmail 互換コマンドと言ってるし、実際動いたのでこれでいいや。
使用例。
$ cat mail_message |/usr/sbin/sendmail -oi -f from@infoseek.jp to@example.com
SENDMAIL(1) sendmail - Postfix Sendmail 互換インターフェース
http://www.kobitosan.net/postfix/jman/sendmail.1.html
-f sender
エンベロープの送信者アドレスをセットします。これは
メッセージが Errors-To: メッセージヘッダを含まない
場合に配送の問題が送られる場所です。
なぜか私の Linux マシンには sendmail(1) の man page がインストールされてなかった。sendmail(8) の man page はある。仕方がないので、postfix の sendmail コマンドの man pageを参照。sendmail 互換コマンドと言ってるし、実際動いたのでこれでいいや。
2004-10-09 で書いた「添付ファイル付メールを送信する Ruby スクリプト」である samail 0.3 を修正して バージョン 0.4 とした。
・状況表示メッセージは標準エラー出力に出力するようにした。
・--output - を指定されたときは、SMTP にメールを投げずに標準出力のみに出力するようにした。
・setup メソッド内で初期化した変数を他のメソッドで参照するのはやっぱり違和感があるので setup メソッドを削除。グローバルなんだからいいんだろうけど。
ローカルの sendmail コマンドに samail の出力を渡す例。
- samail 0.4 の修正点
・smtp タイムアウト時のエラーを rescue Exception で捕捉するようにした。・状況表示メッセージは標準エラー出力に出力するようにした。
・--output - を指定されたときは、SMTP にメールを投げずに標準出力のみに出力するようにした。
・setup メソッド内で初期化した変数を他のメソッドで参照するのはやっぱり違和感があるので setup メソッドを削除。グローバルなんだからいいんだろうけど。
- samail 0.4 で便利になった点
標準出力にメールの中身を出力するようにしたので、ローカルのメール送信コマンドを利用することができるようになった。これにより、samail の簡易な SMTP リトライ機能ではなくローカルの MTA が提供する強力かつ信頼性の高いリトライ機能を利用できる。また、samail はリトライのみでキューイング機能を持たないが、ローカル MTA はキューイング機能を持っていればそれを利用できる。ローカルの sendmail コマンドに samail の出力を渡す例。
$ samail -v --to "sonic64@infoseek.jp example@example.com" --from sonic64@infoseek.jp --attachment "logo.png /tmp/backup.tar.bz2" |/usr/sbin/sendmail -f sonic64@infoseek.jp -oi "sonic64@infoseek.jp example@example.com"
- samil 0.4 ソース
ライセンスは 2004-10-09 でも書いたとおり、GPL2 と BSD のデュアルライセンス。#!/usr/local/bin/ruby
# Copyright (C) 2004 Saito Hiroaki <sonic64@infoseek.jp>
# http://sonic64.com/
require 'kconv'
require 'net/smtp'
require 'getopts'
APPLICATION_NAME = 'Landscape Mailsender'
APPLICATION_VERSION = '0.4'
BANNER_STRING = APPLICATION_NAME + ' ' + APPLICATION_VERSION
X_MAILER_WEBSITE = 'http://sonic64.com/2004-11-01.html'
def build_mail_header()
$mail_content << 'Date: ' + Time::now.strftime("%a, %d %b %Y %X %z") + "\n"
$mail_content << 'From: ' + $mail_from + "\n"
$mail_content << 'To: ' + $mail_to.join(', ') + "\n"
$mail_content << 'Subject: ' + $mail_subject + "\n"
$mail_content << "MIME-Version: 1.0\n"
$mail_content << 'Content-Type: multipart/mixed; boundary="' + $boundary + "\"\n"
$mail_content << 'X-Mailer: ' + BANNER_STRING + "\n"
$mail_content << 'X-Mailer-WebSite: ' + X_MAILER_WEBSITE + "\n"
$mail_content << "\n"
end
def add_attchment(file_name)
if file_name == '' then
return
end
attachment_file = File.open(file_name).readlines.join('')
encoded_attachment = [attachment_file].pack('m')
$mail_content << '--' + $boundary + "\n"
$mail_content << "Content-Type: application/octet-stream;\n"
$mail_content << ' name="' + File.basename(file_name) + '"' + "\n"
$mail_content << "Content-Transfer-Encoding: base64\n"
$mail_content << "Content-Disposition: attachment;\n"
$mail_content << ' filename="' + File.basename(file_name) + "\"\n\n"
$mail_content << encoded_attachment + "\n"
end
def send_mail(retry_count)
begin
STDERR.puts Time::now.to_s + " Try to connect " + $smtp_server if $OPT_v
Net::SMTP.start($smtp_server) do |smtp|
smtp.sendmail($mail_content, $mail_from, $mail_to)
end
STDERR.puts Time::now.to_s + ' Send OK' if $OPT_v
rescue Exception => e
STDERR.puts Time::now.to_s + ' smtp error: ' + e.message
if retry_count != 0 then
retry_count -= 1
STDERR.puts Time::now.to_s + ' sleep: ' + $smtp_retry_interval_second.to_s + 'sec'
sleep($smtp_retry_interval_second)
$smtp_retry_interval_second *= 2
retry
else
STDERR.puts Time::now.to_s + ' abort: Over retry count'
raise
end
end
end
# main
usage_message = "usage: #$0 [-v] --to TO_EMAIL_ADDRESS [--from FROM_EMAIL_ADDRESS] [--smtp SMTP_SERVER] [--attachment ATTACHMENT_FILE] [--output]"
unless getopts('v', 'from:', 'to:', 'subject:', 'attachment:', 'smtp:', 'output:')
abort usage_message
end
abort "#$0: specifiy --to TO_EMAIL_ADDRESS\n" + usage_message if ! $OPT_to
if $OPT_output == '-' then
$output2stdout = true
$smtp_server = ''
elsif $OPT_smtp then
$output2stdout = false
$smtp_server = $OPT_smtp
else
$smtp_server = 'localhost'
end
$mail_from = $OPT_from ? $OPT_from : ENV['USER'] + '@' + ENV['HOSTNAME']
$mail_to = $OPT_to.split(/,\s*|\s+/)
$mail_subject = $OPT_subject ? $OPT_subject : APPLICATION_NAME + ' [' + Time::now.strftime("%a, %d %b %Y %X %z") + ']'
$mail_content = ''
$boundary = 'boundary_string_by_landscape_mailsender'
$attachment_file = $OPT_attachment ? $OPT_attachment.split(/,\s*|\s+/) : []
$smtp_retry = 8
$smtp_retry_interval_second = 30
if $OPT_v then
STDERR.puts 'To: ' + $mail_to.join(', ')
STDERR.puts 'From: ' + $mail_from
STDERR.puts 'Attachment file: ' + $attachment_file.join(", ")
STDERR.puts 'Subject: ' + $mail_subject
if $output2stdout then
STDERR.puts 'Output to STDOUT'
else
STDERR.puts 'SMTP Server: ' + $smtp_server
end
end
build_mail_header()
$mail_content << '--' + $boundary + "\n"
$mail_content << "Content-Type: text/plain; charset=iso-2022-jp\n"
$mail_content << "Content-Transfer-Encoding: 7bit\n"
$mail_content << "\n"
$mail_content << "-- \n"
$mail_content << 'Powered by ' + BANNER_STRING + "\n"
$mail_content << X_MAILER_WEBSITE + "\n"
$mail_content << "\n"
$attachment_file.each do |file|
add_attchment(file)
end
$mail_content << '--' + $boundary + "--\n"
if $output2stdout then
puts $mail_content
else
send_mail($smtp_retry)
end
コマンドラインから添付ファイル付きメールを送信する Ruby スクリプト samail を作成した。Send Attachment MAIL の略で、samail。読み方は「さめいる」または「えすえーめいる」かなあ。
2003-12-12 の「添付ファイル付きメールをコマンドラインから送信」や 2004-07-02 の「添付ファイル付メールを送信する Perl/Rubyスクリプト」 でもいろいろ書いたけど、Ruby 1.8 が使えるなら今回書いたスクリプトの方がカスタマイズはしやすい。
Ruby 1.8 の標準ライブラリしか使っていないため、Ruby さえインストールしてあれば動作する。
To, From, Subject を指定可能。To には複数のアドレスを指定可能。
Cc と Bcc には未対応。
SMTP サーバが必要。ローカルの MDA を呼び出す機能は未実装。
SMTP 失敗時には自動的にリトライする。初期設定では3回までリトライ。
ruby 1.8.1 (2003-12-25) [i386-cygwin]
ファイルの文字コードは ASCII しか使ってないので何でも良い。改行コードは LF が良い。
chmod 744 などどして、ファイル samail に実行権限を付与。
以上で完了。
to や attachment には複数の値を指定できる。その場合、ダブルクオートかシングルクオートで値をくくり、それぞれの値はカンマかスペースで区切る。
-v オプションを指定していると、標準出力に To, From, 添付ファイルのパス, subject, 使用する SMTP サーバ名を表示する。"Try to connect ..." はメール本文の生成が完了し、SMTP サーバに接続しようとした時点で表示する。Send OK は SMTP サーバへの送信を完了したときに表示する。
samail は X-Mailer などで Landscape Mailsender を名乗る。
http://www.loveruby.net/ja/prog/tmail.html
vCard ファイルを添付したメールを作る
http://namazu.org/~satoru/attic/vcardmail.rb
SSTP Bottle メール送信クライアント
http://www.tenchi.ne.jp/~yoko/haruna/
2003-12-12 の「添付ファイル付きメールをコマンドラインから送信」や 2004-07-02 の「添付ファイル付メールを送信する Perl/Rubyスクリプト」 でもいろいろ書いたけど、Ruby 1.8 が使えるなら今回書いたスクリプトの方がカスタマイズはしやすい。
- samail の概要
コマンドラインで動作する、SMTP を利用したメール送信プログラム。Ruby 1.8 の標準ライブラリしか使っていないため、Ruby さえインストールしてあれば動作する。
- samail の機能
添付ファイルを好きな数だけ指定して送信できる。To, From, Subject を指定可能。To には複数のアドレスを指定可能。
Cc と Bcc には未対応。
SMTP サーバが必要。ローカルの MDA を呼び出す機能は未実装。
SMTP 失敗時には自動的にリトライする。初期設定では3回までリトライ。
- samail の動作確認環境
ruby 1.8.1 (2003-12-25) [i586-linux]ruby 1.8.1 (2003-12-25) [i386-cygwin]
- samil のインストール
後述する samail ソースをコピー & ペーストして、samail というファイル名を付けてパスの通ったディレクトリに保存。ファイルの文字コードは ASCII しか使ってないので何でも良い。改行コードは LF が良い。
chmod 744 などどして、ファイル samail に実行権限を付与。
以上で完了。
- samail の使い方と動作例
以下のようにコマンドラインから必要なオプションを渡す。to や attachment には複数の値を指定できる。その場合、ダブルクオートかシングルクオートで値をくくり、それぞれの値はカンマかスペースで区切る。
$ samail -v --to "sonic64@infoseek.jp example@example.com" --from sonic64@infoseek.jp --smtp smtp.example.com --attachment "logo.png /tmp/backup.tar.bz2"
-v オプションを指定していると、標準出力に To, From, 添付ファイルのパス, subject, 使用する SMTP サーバ名を表示する。"Try to connect ..." はメール本文の生成が完了し、SMTP サーバに接続しようとした時点で表示する。Send OK は SMTP サーバへの送信を完了したときに表示する。
To: sonic64@infoseek.jp, example@example.com
From: sonic64@infoseek.jp
Attachment file: logo.png, /tmp/backup.tar.bz2
Subject: Landscape Mailsender Sat, 09 Oct 2004 20:35:34 +0900]
SMTP Server: smtp.example.com
Try to connect smtp.example.com
Send OK
samail は X-Mailer などで Landscape Mailsender を名乗る。
- ライセンス
何が良いんだろう? とりあえず GPL2 と BSD のデュアルライセンスにしておけばいいのかな。- samail ソース
#!/usr/local/bin/ruby
# Copyright (C) 2004 Saito Hiroaki <sonic64@infoseek.jp>
# http://sonic64.com/
require 'kconv'
require 'net/smtp'
require 'getopts'
def setup()
$APPLICATION_NAME = 'Landscape Mailsender'
$VERSION = '0.3'
$BANNER_STRING = $APPLICATION_NAME + ' ' + $VERSION
$X_MAILER_WEBSITE = "http://sonic64.com/2004-10-09.html"
$smtp_server = $OPT_smtp? $OPT_smtp : 'localhost'
$mail_from = $OPT_from ? $OPT_from : ENV['USER'] + '@' + ENV['HOSTNAME']
$mail_to = $OPT_to.split(/,\s*|\s+/)
$mail_subject = $OPT_subject ? $OPT_subject : $APPLICATION_NAME + ' [' + Time::now.strftime("%a, %d %b %Y %X %z") + ']'
$mail_content = ''
$boundary = 'boundary_string_by_landscape_mail'
$attachment_file = $OPT_attachment ? $OPT_attachment.split(/,\s*|\s+/) : []
$smtp_retry = 3
if ($OPT_v) then
puts 'To: ' + $mail_to.join(', ')
puts 'From: ' + $mail_from
puts 'Attachment file: ' + $attachment_file.join(", ")
puts 'Subject: ' + $mail_subject
puts 'SMTP Server: ' + $smtp_server
end
end
def build_mail_header()
$mail_content << 'Date: ' + Time::now.strftime("%a, %d %b %Y %X %z") + "\n"
$mail_content << 'From: ' + $mail_from + "\n"
$mail_content << 'To: ' + $mail_to.join(', ') + "\n"
$mail_content << 'Subject: ' + $mail_subject + "\n"
$mail_content << "MIME-Version: 1.0\n"
$mail_content << 'Content-Type: multipart/mixed; boundary="' + $boundary + "\"\n"
$mail_content << 'X-Mailer: ' + $BANNER_STRING + "\n"
$mail_content << 'X-Mailer-WebSite: ' + $X_MAILER_WEBSITE + "\n"
$mail_content << "\n"
end
def add_attchment(file_name)
if file_name == '' then
return
end
attachment_file = File.open(file_name).readlines.join('')
encoded_attachment = [attachment_file].pack('m')
$mail_content << '--' + $boundary + "\n"
$mail_content << "Content-Type: application/octet-stream;\n"
$mail_content << ' name="' + File.basename(file_name) + '"' + "\n"
$mail_content << 'Content-Transfer-Encoding: base64' + "\n"
$mail_content << "Content-Disposition: attachment;\n"
$mail_content << ' filename="' + File.basename(file_name) + "\"\n\n"
$mail_content << encoded_attachment + "\n"
end
def send_mail(retry_count)
begin
puts "Try to connect " + $smtp_server if $OPT_v
Net::SMTP.start($smtp_server) do |smtp|
smtp.sendmail($mail_content, $mail_from, $mail_to)
end
puts 'Send OK' if $OPT_v
rescue
puts 'smtp error occurred'
if retry_count != 0 then
retry_count -= 1
send_mail(retry_count)
else
puts 'abort: Over retry count'
raise
end
end
end
# main
unless getopts('v', 'from:', 'to:', 'subject:', 'attachment:', 'smtp:')
abort "usage: #$0 [-v] --to TO_EMAIL_ADDRESS [--from FROM_EMAIL_ADDRESS] [--smtp SMTP_SERVER] [--attachment ATTACHMENT_FILE]"
end
setup()
build_mail_header()
$mail_content << '--' + $boundary + "\n"
$mail_content << "Content-Type: text/plain; charset=iso-2022-jp\n"
$mail_content << "Content-Transfer-Encoding: 7bit\n"
$mail_content << "\n"
$mail_content << "-- \n"
$mail_content << 'Powered by ' + $BANNER_STRING + "\n"
$mail_content << $X_MAILER_WEBSITE + "\n"
$mail_content << "\n"
$attachment_file.each do |file|
add_attchment(file)
end
$mail_content << '--' + $boundary + "--\n"
send_mail($smtp_retry)
- 参考にしたもの
TMailhttp://www.loveruby.net/ja/prog/tmail.html
vCard ファイルを添付したメールを作る
http://namazu.org/~satoru/attic/vcardmail.rb
SSTP Bottle メール送信クライアント
http://www.tenchi.ne.jp/~yoko/haruna/
- 2004年11月1日追記 2004-11-01 に samail 0.4 について書いた。
メールサーバが増えたので、2003-12-08 に書いた .fetchmailrc を修正して複数のサーバのメールを fetchmail するようにした。
set postmaster hiroaki
set nobouncemail
defaults
protocol pop3
keep
smtphost localhost
mda "/usr/bin/procmail"
poll 10.50.200.3
user "私の名前"
pass PASSWORD
poll 10.99.31.3
user saitou@example.com
pass PASSWORD
添付ファイル付きメールを送信すると、大容量ファイルを保存した URL を書いたメールを本来の受取人に送ってくれるというサービス。
sonic64@infoseek.jp に大容量メールを送りたい場合、sonic64@infoseek.jpgw.jp に送るだけ。事前登録とかは不要。
テンプメール - Easy to use attachment file.
http://www.tempmail.jp/
メールの中身
メールのメッセージ ID を URL として利用しているようだ。
http://freecache.org/http://www.jpgw.jp/get.php?m=0/20040715 ... へのリンクを設定した html を作成し、右クリックして「対象をファイルに保存」を選択すると、freecache.org からダウンロードすることができた。問題なく使えるようだ。
Internet Archive、誰でも利用可能な分散キャッシュ「FreeCache」を公開
http://internet.watch.impress.co.jp/cda/news/2004/05/13/3092 ...
事前登録なしで使えるのは 10MB だけだが、それなりに重宝しそうだ。10MB 以上のファイルを送りたい場合は複数のメールに分けなければならないが。ユーザ側で気を付けなければならないのはセキュリティだ。インターネット上に添付ファイルが生で晒され、URL を知っている人なら誰でもダウンロードできてしまう。見られたくないデータはファイルの暗号化をした方が良い。だれでもダウンロードできるという性質を逆手に取って、FreeCache と組み合わせるという技も使えるが、保存期間が24時間という制約がネックになるかな。
sonic64@infoseek.jp に大容量メールを送りたい場合、sonic64@infoseek.jpgw.jp に送るだけ。事前登録とかは不要。
テンプメール - Easy to use attachment file.
http://www.tempmail.jp/
使い方
(1) ご自分のメールソフトでメールを作成
(2) あて先メールアドレスにgw.jpを付け加える
(例)
taro@tempmail.jp
↓
taro@tempmail.jpgw.jp
(gwの前に .は不要です)
(3) 送信する
制限事項
・1通のサイズは200Mバイトまで。
(未登録利用は10MBまで)
・ファイルの保持期間は24時間です。
・HTMLメールには対応していません。
- tempmail を使ってみる
Yahoo Mail のアカウントから sonic64@infoseek.jpgw.jp に添付ファイル付きメールを送ってみる。やってみると、sonic64@infoseek.jp には添付ファイルが保存された URL が書かれたメールが送られてきた。メールの中身
ファイル名: cl-full.xml
http://www.jpgw.jp/get.php?m=0/20040715232914.62031.qmail@web602.mail.yahoo.co.jp&a=1&u=1
ファイル名: cl.xml
http://www.jpgw.jp/get.php?m=0/20040715232914.62031.qmail@web602.mail.yahoo.co.jp&a=2&u=1
メールのメッセージ ID を URL として利用しているようだ。
- Internet Archive の FreeCache と組み合わせる
URL の頭に http://freecache.org/ を付ければ Internet Archive が分散キャッシュを提供してくれる FreeCache というサービスがある。tempmail と FreeCache を組み合わせて利用できるかをテスト。http://freecache.org/http://www.jpgw.jp/get.php?m=0/20040715 ... へのリンクを設定した html を作成し、右クリックして「対象をファイルに保存」を選択すると、freecache.org からダウンロードすることができた。問題なく使えるようだ。
Internet Archive、誰でも利用可能な分散キャッシュ「FreeCache」を公開
http://internet.watch.impress.co.jp/cda/news/2004/05/13/3092 ...
- 簡単に使えるのが良い
tempmail の良さは、簡単に使えるということ。送り先のメールアドレスにgw.jp を付加するだけという潔さ。事前登録なしで使えるのは 10MB だけだが、それなりに重宝しそうだ。10MB 以上のファイルを送りたい場合は複数のメールに分けなければならないが。ユーザ側で気を付けなければならないのはセキュリティだ。インターネット上に添付ファイルが生で晒され、URL を知っている人なら誰でもダウンロードできてしまう。見られたくないデータはファイルの暗号化をした方が良い。だれでもダウンロードできるという性質を逆手に取って、FreeCache と組み合わせるという技も使えるが、保存期間が24時間という制約がネックになるかな。
debian のパッケージリストの mpack のページを見ていたら、より高性能な uudeview/uuenview を使えと書いてあった。
http://packages.debian.org/unstable/mail/mpack.ja.html
mpack は添付ファイル付きメール送信ツールとして 2003-12-12 から使っているツールだ。from ヘッダを指定できないのが玉に瑕だが、私の環境では健気に頑張ってくれている。
その mpack からの乗り換えをメンテナが推奨するくらいだから、uudeview はよほど多機能で優れたツールなんだろう。試す価値はある。そういえば、cygwin でも mpack を使いたいと思ってたんだけど、インストールしていざ実行しようとしたら 以下のようなエラーとなって使えなかった。乗り換えればこの問題を解決できるかもしれない。
Manpage of UUDEVIEW
http://www.linux.or.jp/JM/html/uudeview/man1/uudeview.1.html
たとえば cygwin だとデフォルトで MTA をインストールしない。もしかしたら MUA もなかったかも。きちんと環境設定するのは大変かも。
Installing UUDeview for Unix
http://www.fpx.de/fp/Software/UUDeview/Install-Unix.html#con ...
ここらへんを設定すればメール送信機能が使えるようになるのか。でも手間だな。まあ、メール送信機能抜きでインストールしてみよう。なんだか趣旨変わってる気がするけど。
なんで同じファイルだよって言われるんだろう? シンボリックリンク・・・じゃあないよね。cygwin 環境固有の何かが悪さをしているのかな。Google で cygwin uudeview を検索すると、以下のようにしてインストールした例があった。
Cygwin Install and Setting (II)
http://www-step.kugi.kyoto-u.ac.jp/~futaana/Misc/Comp/cygwin ...
上記方法でインストールできた。
メール送信を試したところ、予想通りエラー。まあいいや。base64 や uuencode のエンコーダ/デコーダとしては使えるし。たぶんそんな機会は無いと思うけど。
結局 mpack からの乗り換えはなし。添付ファイル付きメール送信だけやりたいんだったら、やっぱり Perl なり Ruby なりでスクリプト書くのがいいのかなー。よし、そうしよう。ちょっとやる気出てきたし。
http://packages.debian.org/unstable/mail/mpack.ja.html
munpack の代わりとして、パッケージメンテナはより多才なパッケージである uudeview を推奨します。
mpack は添付ファイル付きメール送信ツールとして 2003-12-12 から使っているツールだ。from ヘッダを指定できないのが玉に瑕だが、私の環境では健気に頑張ってくれている。
その mpack からの乗り換えをメンテナが推奨するくらいだから、uudeview はよほど多機能で優れたツールなんだろう。試す価値はある。そういえば、cygwin でも mpack を使いたいと思ってたんだけど、インストールしていざ実行しようとしたら 以下のようなエラーとなって使えなかった。乗り換えればこの問題を解決できるかもしれない。
$ mpack -s "[ChangeLog Pack] `date`" attachment.tar.gz saitou-hiroaki@example.com
execv: No such file or directory
- uudeview ってどんなツール?
Google で uudeview を検索すると、JM に収録された man page がヒット。ざっと読んでみる。要するに Base64 や uuencode のエンコーダ/デコーダのセットのようだ。添付ファイル付きメールを送る機能もある。といっても、自前で SMTP で通信するわけではないようだ。ローカルの MTA や SMTP クライアントと連携する機能を持っているということらしい。Manpage of UUDEVIEW
http://www.linux.or.jp/JM/html/uudeview/man1/uudeview.1.html
メール送信やニュース投稿を自動的に行わせるには、 uuenview をコンパイル時に正しく設定しなければならない。うまく動作しない場合には、システム管理者に相談すること。ニュースの投稿に使われるプログラムは、環境変数 INEWS を使って実行時に設定することができる。この設定はコンパイル時の設定よりも優先される。
たとえば cygwin だとデフォルトで MTA をインストールしない。もしかしたら MUA もなかったかも。きちんと環境設定するのは大変かも。
Installing UUDeview for Unix
http://www.fpx.de/fp/Software/UUDeview/Install-Unix.html#con ...
--enable-sendmail=PROG
Use PROG to mail messages to the internet. The program is given a list of white-space separated recipients on the command line and is fed the mail message, including headers, via standard input. One use of this option is to define a program doing certain preprocessing on the message before handing it over to the mail system.
If this option is not used, the configuration script does try to locate certain common mail agents by itself, with sendmail being the first choice.
You can also use --disable-sendmail to disable the mail sending facility altogether.
ここらへんを設定すればメール送信機能が使えるようになるのか。でも手間だな。まあ、メール送信機能抜きでインストールしてみよう。なんだか趣旨変わってる気がするけど。
- configure、make、 インストール
UUDeview Home Page http://www.fpx.de/fp/Software/UUDeview/ から、uudeview-0.5.20.tar.gz を取得して tar を展開。tcl を要求されるので無効にして configure する。$ ./configure --disable-tclここまではうまくいったのだが、make install で cp のエラー。
$ make
$ make install
(cd uulib ; make)
make[1]: Entering directory `/home/Administrator/tmp/uudeview-0.5.20/uulib'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/Administrator/tmp/uudeview-0.5.20/uulib'
(cd unix ; make)
make[1]: Entering directory `/home/Administrator/tmp/uudeview-0.5.20/unix'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/Administrator/tmp/uudeview-0.5.20/unix'
for d in uudeview uuenview ; do \
./install-sh -c unix/$d /usr/local/bin/$d ; \
done
cp: `unix/uudeview' and `/usr/local/bin/#inst.3284#' are the same file
cp: `unix/uuenview' and `/usr/local/bin/#inst.3024#' are the same file
make: *** [install-uudeview] Error 1
なんで同じファイルだよって言われるんだろう? シンボリックリンク・・・じゃあないよね。cygwin 環境固有の何かが悪さをしているのかな。Google で cygwin uudeview を検索すると、以下のようにしてインストールした例があった。
Cygwin Install and Setting (II)
http://www-step.kugi.kyoto-u.ac.jp/~futaana/Misc/Comp/cygwin ...
2002/10/08 http://www.fpx.de/fp/Software/UUDeview/download/ からsourceを取得(0.5.18)。解答後、
% ./configure --disable-tcl
% make
% install unix/uudeview.exe /usr/local/bin
% install unix/uuenview.exe /usr/local/bin
上記方法でインストールできた。
- uuenview の添付ファイル付きメール送信機能を試す
$ uuenview -m 'saitou-hiroaki@example.com' attachment.tar.gz
error: Cannot Email file: option not configured
メール送信を試したところ、予想通りエラー。まあいいや。base64 や uuencode のエンコーダ/デコーダとしては使えるし。たぶんそんな機会は無いと思うけど。
結局 mpack からの乗り換えはなし。添付ファイル付きメール送信だけやりたいんだったら、やっぱり Perl なり Ruby なりでスクリプト書くのがいいのかなー。よし、そうしよう。ちょっとやる気出てきたし。
- 2004-10-09 追記
Ruby 1.8 の標準ライブラリだけで動作する添付ファイル付きメール送信スクリプトを 2004-10-09 に書いた。コマンドラインから添付ファイル付きメールを送信したい。cron で定期的にメール送信するバッチが必要になった。
エラーを追求する手間をかけるよりも、今回は他の解決策を探した方が良いと私のゴーストがささやいている。「From の指定」など、mpack には無い機能も使いたいし。というわけで、今回は Perl か Ruby で SMTP と Content-Type: multipart/mixed; を扱うスクリプトを書くことにしよう。
ActivePerlからメールを送る
http://member.nifty.ne.jp/hippo2000/perltips/perlmail.htm
さすがは Perl、全くスクリプトを書かなくてもやりたいことを達成できてしまった。
Google で ruby 添付ファイル メール 送信を検索。なんだかあまりヒットしないな。こういう細かい仕事を自動化するスクリプトの需要は結構あると思うんだけどな。検索語が悪いのかも。英語でやってみよう。Google で ruby base64 mail attachment を検索。[ruby-list:30312] composing a mail with a big file attached がヒット。なるほど、Tmail という便利なライブラリがあるんだね。
TMail
http://www.loveruby.net/ja/prog/tmail.html
オフィシャルサイトの説明には「Ruby 用 メール総合ライブラリ」って書いてある。かなり高機能なライブラリのようだ。あ、Tmail の作者は 「Rubyソースコード完全解説」や「Ruby レシピブック」で有名な青木さんだ。
tar を展開して、
setup.rb config
setup.rb setup
setup.rb install
を実行するだけ。
コンパイルの時にいろいろエラーがでたけど、セットアップスクリプトが ignore するよって言ってるんだから気にしないことにする。
さて、この便利なライブラリ Tmail を使えば、簡単に添付ファイル付きメール送信スクリプトが書けるだろう。でも、やっぱりだれかが同じようなスクリプトを書いているはず。それを探して使うほうが早いだろう。ウェブを探してみると、高林さんが書いた「vCard ファイルを添付したメールを作る」が Tmail を使っている。短いし、これをちょっと修正すればやりたいことは達成できそう。
vCard ファイルを添付したメールを作る
http://namazu.org/~satoru/attic/vcardmail.rb
- 2003-12-12 でも同じ記事を書いたけど
2003-12-12 にも同じ「添付ファイル付きメールをコマンドラインから送信」という記事を書いたが、あれは Linux での話だ。今回は cygwin で同じことをやりたい。本当は前回の記事でも使った mpack を cygwin 環境でコンパイルして使おうと思ったんだけど、コンパイルエラーとなってしまった。エラーを追求する手間をかけるよりも、今回は他の解決策を探した方が良いと私のゴーストがささやいている。「From の指定」など、mpack には無い機能も使いたいし。というわけで、今回は Perl か Ruby で SMTP と Content-Type: multipart/mixed; を扱うスクリプトを書くことにしよう。
- Perl で添付ファイル付きメールを送信
Perl であれば、すでに添付ファイル付きメール送信スクリプトのサンプルが河馬屋二千年堂のウェブサイトにあったはずなので、それを使えばいい。このサンプルを動かすには、いくつか必要なモジュールがある。その部分だけ引用しておく。ActivePerlからメールを送る
http://member.nifty.ne.jp/hippo2000/perltips/perlmail.htm
添付ファイル付のメールを送信する + 日本語への対応+HTMLメール
use Net::SMTP;
use MIME::Entity;
use MIME::Words qw (:all);
require 'jcode.pl';
さすがは Perl、全くスクリプトを書かなくてもやりたいことを達成できてしまった。
- RUby で添付ファイル付きメールを送信
Ruby は標準インストールされるライブラリが充実してるから、もしかしたら smtp や base64 を扱うクラス、果ては添付ファイル付きメール送信クラスなんてものまで標準で用意されてるかも。ちょっと期待。Google で ruby 添付ファイル メール 送信を検索。なんだかあまりヒットしないな。こういう細かい仕事を自動化するスクリプトの需要は結構あると思うんだけどな。検索語が悪いのかも。英語でやってみよう。Google で ruby base64 mail attachment を検索。[ruby-list:30312] composing a mail with a big file attached がヒット。なるほど、Tmail という便利なライブラリがあるんだね。
TMail
http://www.loveruby.net/ja/prog/tmail.html
オフィシャルサイトの説明には「Ruby 用 メール総合ライブラリ」って書いてある。かなり高機能なライブラリのようだ。あ、Tmail の作者は 「Rubyソースコード完全解説」や「Ruby レシピブック」で有名な青木さんだ。
- Tmail のインストール
cygwin でも無事インストールできた。tar を展開して、
setup.rb config
setup.rb setup
setup.rb install
を実行するだけ。
コンパイルの時にいろいろエラーがでたけど、セットアップスクリプトが ignore するよって言ってるんだから気にしないことにする。
さて、この便利なライブラリ Tmail を使えば、簡単に添付ファイル付きメール送信スクリプトが書けるだろう。でも、やっぱりだれかが同じようなスクリプトを書いているはず。それを探して使うほうが早いだろう。ウェブを探してみると、高林さんが書いた「vCard ファイルを添付したメールを作る」が Tmail を使っている。短いし、これをちょっと修正すればやりたいことは達成できそう。
vCard ファイルを添付したメールを作る
http://namazu.org/~satoru/attic/vcardmail.rb
- スクリプト完成、いざメール送信
高林さんのスクリプトほとんどそのまま。元のスクリプトが GPL2 なので、以下のスクリプトのライセンスも GPL2。#!/usr/bin/env ruby
require 'kconv'
require 'tmail'
require 'net/smtp'
def generate_filename (vcard)
/^FN:(.*)/ =~ vcard
name = $1
"=?ISO-2022-JP?B?" + (name + '.vcf').tojis.to_a.pack('m').chomp + "?="
end
raise unless ARGV.length == 2
to = ARGV.shift
vcard = File.open(ARGV.shift).readlines.join('')
mail = TMail::Mail.new
mail.to = to
mail.from = 'example@example.com'
mail.subject = "vcard"
mail.date = Time.now
mail.mime_version = '1.0'
message = TMail::Mail.new
message.set_content_type('text', 'plain')
message.transfer_encoding = '7bit'
message.body = "vcard is attached.\n"
filename = 'atch'
encoded_vcard = [vcard].pack('m').chomp.gsub(/.{76}/, "\\1\n")
attachment = TMail::Mail.new
attachment.body = encoded_vcard
attachment.transfer_encoding = 'base64'
attachment.set_content_type('text', 'x-vcard', 'name' => filename)
attachment.set_content_disposition('attachment',
'filename' => filename)
mail.parts.push(message)
mail.parts.push(attachment)
mail.write_back
$smtp_server = '10.83.0.38'
Net::SMTP.start($smtp_server) do |smtp|
smtp.sendmail(mail.encoded, mail.from, to)
end
- 2004年7月7日追記
って、あれ? この記事はもう少し加筆してから公開しようかと思ってたんだけど、いつの間にか公開状態になってる。まあいいや。上記スクリプトも変数名を直したり、複数添付ファイルに対応しようと思ってた。もしかしたら全く動かないかもしれない。そのうち直す予定。- 2004-10-09 追記
Ruby 1.8 の標準ライブラリだけで動作する添付ファイル付きメール送信スクリプトを 2004-10-09 に書いた。メールシステムを活用するツールを書きたくなった。
POP3 でメールサーバにアクセスして、メールのヘッダだけ取得したい。LIST コマンドを試してみたが、ヘッダは取得できない。なにか良い方法とか便利なコマンドとか無いかなあと思い、Google で pop コマンド ヘッダ 取得を検索するとヒット。TOP というコマンドを使えばいいことがわかった。
ラスト・ワン・ホップ プロトコル「POP3」
http://www.atmarkit.co.jp/fnetwork/rensai/netpro07/netpro01. ...
http://www.ietf.org/rfc/rfc1939.txt
http://www.se.hiroshima-u.ac.jp/~isaki/rfc/rfc1939-jp.txt
7. Optional POP3 Commands
telnet で POP サーバのポート110 に接続して TOP を試してみると、以下のようにメールヘッダだけを表示してくれた。
RFC 1939では TOP コマンド使用時の本文行数指定は必須となっているが、私が利用している POP サーバでは、行数を指定しない場合は 0 で指定したときと同じ挙動を示した。POP サーバの種類とバージョンは不明だけど。
POP3 でメールサーバにアクセスして、メールのヘッダだけ取得したい。LIST コマンドを試してみたが、ヘッダは取得できない。なにか良い方法とか便利なコマンドとか無いかなあと思い、Google で pop コマンド ヘッダ 取得を検索するとヒット。TOP というコマンドを使えばいいことがわかった。
ラスト・ワン・ホップ プロトコル「POP3」
http://www.atmarkit.co.jp/fnetwork/rensai/netpro07/netpro01. ...
●TOP メッセージ番号 Line数
TOPコマンドはRETRコマンドに酷似している。RETRは単にメールメッセージ全体をダウンロードするだけだったが、TOPコマンドは、Line数を指定することでダウンロードするメールメッセージのボディーの行数を指定できる。ヘッダーは必ずダウンロードされる。0とするとメールヘッダーのみ(メールメッセージのうち、最初の空行の部分まで)となるので、主にメール一覧のみ必要としている場合などによく使用される。
- RFC 1939 post office protocol - version 3
RFC1939 によると TOP は POP3 においてはオプション扱い。http://www.ietf.org/rfc/rfc1939.txt
http://www.se.hiroshima-u.ac.jp/~isaki/rfc/rfc1939-jp.txt
7. Optional POP3 Commands
TOP msg n
Arguments:
a message-number (required) which may NOT refer to to a
message marked as deleted, and a non-negative number
of lines (required)
Restrictions:
may only be given in the TRANSACTION state
Discussion:
If the POP3 server issues a positive response, then the
response given is multi-line. After the initial +OK, the
POP3 server sends the headers of the message, the blank
line separating the headers from the body, and then the
number of lines of the indicated message's body, being
careful to byte-stuff the termination character (as with
all multi-line responses).
Note that if the number of lines requested by the POP3
client is greater than than the number of lines in the
body, then the POP3 server sends the entire message.
Possible Responses:
+OK top of message follows
-ERR no such message
Examples:
C: TOP 1 10
S: +OK
S: <the POP3 server sends the headers of the
message, a blank line, and the first 10 lines
of the body of the message>
S: .
...
C: TOP 100 3
S: -ERR no such message
telnet で POP サーバのポート110 に接続して TOP を試してみると、以下のようにメールヘッダだけを表示してくれた。
$ telnet pop.example.com 110
Trying 10.100.79.7...
Connected to pop.example.com
Escape character is '^]'.
+OK POP3 server ready
USER test063
+OK Password required for test063
PASS PASSWORD
+OK test063's maildrop has 1 messages (2052 octets)
TOP 1 0
+OK
Message-Id: <200405050800.d8e8fca2dc0f896fd7cb4cb0031ba249@example.com>
Date: 05 May 2004 17:00:00 +0900
Mime-Version: 1.0
From: "Saito Hiroaki"
<sonic64@example.com>
Subject: 5/5 2
To: "test063@example.com"
<test063@example.com>,
"sonic64@example.com"
<sonic64@example.com>
X-UIDL: 200405050800.d8e8fca2dc0f896fd7cb4cb0031ba249@example.com
Status: RO
Content-Type: text/plain; charset=iso-2022-jp
.
RFC 1939では TOP コマンド使用時の本文行数指定は必須となっているが、私が利用している POP サーバでは、行数を指定しない場合は 0 で指定したときと同じ挙動を示した。POP サーバの種類とバージョンは不明だけど。
TOP 1
+OK
Message-Id: <200405050800.d8e8fca2dc0f896fd7cb4cb0031ba249@example.com>
Date: 05 May 2004 17:00:00 +0900
Mime-Version: 1.0
From: "Saito Hiroaki"
<sonic64@example.com>
Subject: 5/5 2
To: "test063@example.com"
<test063@example.com>,
"sonic64@example.com"
<sonic64@example.com>
X-UIDL: 200405050800.d8e8fca2dc0f896fd7cb4cb0031ba249@example.com
Status: RO
Content-Type: text/plain; charset=iso-2022-jp
.
POP でメールを受信するとき、どうやって受信済みと未受信を管理しているんだろう?
IMAP でメールを読んで、そのあと POP クライアントでメールを受信するとき、未読・既読にかかわらず未受信のメールだけをちゃんと取得してくれる。たぶんクライアント側に何かデータベースがあると思うけど、標準的な仕組みってあるのかな。それに、どうやってメールを一意に特定しているんだろう? Message-ID かな?
Google で メール 受信 重複 仕組みで検索するとトップでヒット。
[becky-ml:18396] 重複して受け取らない仕組みを教えていただけませんか
http://b2search.tietew.net/archive/becky-ml/18396
に対する返答の、[becky-ml:18397] Re: 重複して受け取らない仕組みを教えていただけませんか
http://b2search.tietew.net/archive/becky-ml/18397
なるほど、受信したメールにあった X-UIDL というヘッダはこれのことだったのか。
開いてみると、中は3行しかなかった。
あ、そういえば私はサーバをメールに残す設定にしてなかったんだっけ。サーバにメールを残すように設定を変更して、と。
おお、なるほど。1行目に POP サーバ名とユーザ名、2行目に UIDL か。
IMAP でメールを読んで、そのあと POP クライアントでメールを受信するとき、未読・既読にかかわらず未受信のメールだけをちゃんと取得してくれる。たぶんクライアント側に何かデータベースがあると思うけど、標準的な仕組みってあるのかな。それに、どうやってメールを一意に特定しているんだろう? Message-ID かな?
Google で メール 受信 重複 仕組みで検索するとトップでヒット。
[becky-ml:18396] 重複して受け取らない仕組みを教えていただけませんか
http://b2search.tietew.net/archive/becky-ml/18396
に対する返答の、[becky-ml:18397] Re: 重複して受け取らない仕組みを教えていただけませんか
http://b2search.tietew.net/archive/becky-ml/18397
ツール→プロトコルログを取る、を ON にしてサーバとのやりとりを眺めて
みてください。すると
UIDL
+OK
1 10c0035cb84ff36f078b26fe89050b6c
2 1504786cef65214303beb3426b51fd3f
こんなのがあると思います。UIDL というのは Becky! が投げたコマンドで、
その後はサーバの応答です。 UIDL というのは POP3 サーバがメールに対し
て 1 意に割り振る ID です。(この例では 2 通メールがありますの)
サーバにメールを残す設定では、Becky!はこの情報をデータフォルダのなか
の "ユーザー名@サーバ名.dat"というファイルに保存しています。他のソフ
トでも同様のファイルがあるはずです。受信時にこのファイルの情報とサー
バが返してきた UIDL を比較して、受信済みかそうでないかを区別し
ています。
なるほど、受信したメールにあった X-UIDL というヘッダはこれのことだったのか。
- Netscape Messanger ではどこに UIDL を保存してるの?
Netscape のユーザプロファイル保存ディレクトリを探してみる。mail というディレクトリがあるから、きっとこの中だろう。ん、これかな? popstate.dat とは、いかにも状態管理してそうなファイル名だ。開いてみると、中は3行しかなかった。
# Netscape POP3 State File
# This is a generated file! Do not edit.
あ、そういえば私はサーバをメールに残す設定にしてなかったんだっけ。サーバにメールを残すように設定を変更して、と。
# Netscape POP3 State File
# This is a generated file! Do not edit.
*mail.example.com hiroaki
d eF:"!#hN"!NN%"!e^~!!
おお、なるほど。1行目に POP サーバ名とユーザ名、2行目に UIDL か。
fetchmail にログを出力させるために、.fetchmailrc に以下を記述したが、ログが出力されない。
文法が間違ってるのかな、と思って Google で set logfile fetchmailrc を検索したところヒット。文法は正しかったが、fetchmail の仕様で出力されなかったようだ。
[debian-users:37402] Re: fetchmail の log機能
http://lists.debian.or.jp/debian-users/200306/msg00175.html
set logfile "/home/hiroaki/log/fetchmail/fetchmail_setlogfile.log"
文法が間違ってるのかな、と思って Google で set logfile fetchmailrc を検索したところヒット。文法は正しかったが、fetchmail の仕様で出力されなかったようだ。
[debian-users:37402] Re: fetchmail の log機能
http://lists.debian.or.jp/debian-users/200306/msg00175.html
$ man -LC fetchmail
[...]
The -L <filename> or --logfile <filename> option
(keyword: set logfile) allows you to redirect status
messages emitted while detached into a specified
^^^^^^^^^^^^^^
logfile (follow the option with the logfile name).
[...]
ということで detach、言い換えると background(あるいは
daemon) として動作しないとログをファイルに記録しないことが仕
様のようです。
松田陽一さんの ~/.fetchmailrc の内容は分かりませんが
"fetchmail --logfile ~/fetchmaillog -v -v" でデーモン動作し
ないならログファイルが存在しないときログをファイルに記録しな
いことになりそうです。
ちなみに私は fetchmail をデーモン動作させて使用していますが、
『ログファイルは「なければ自動的に作成」』しています。
ログファイルが存在するとデーモン動作させなくてもログをファイ
ルに記録しますよね? 一貫性がなくてなんだか良く分からない仕様・
動作ではあります。はい。
cron で定期的に添付ファイル付きメールを送りたい。
添付ファイルは tar で生成する。さて、メールをどうやって生成しよう。普段ならスクリプトを書くところだが、今日はあり合わせのコマンド群でできるならそれを使いたい気分。
早速 Google で linux コマンドライン 添付ファイル メール 送信を検索。linux-users の記事などがヒット。いくつかスクリプトやコマンドが紹介されていたが、mpack というツールを使うことにした。
[linux-users:83133] Re: sendmailで添付ファイルをつけて送れるか?
http://search.luky.org/linux-users.8/msg03133.html
mpack
ftp://ftp.andrew.cmu.edu/pub/mpack/
メール本文を指定できないとか、いくつか不満はあるがとりあえずはこれでもいい。
・・・と思ったが、from を指定できないのはダメだな。やはりスクリプトを書かなければならないか・・・。
添付ファイルは tar で生成する。さて、メールをどうやって生成しよう。普段ならスクリプトを書くところだが、今日はあり合わせのコマンド群でできるならそれを使いたい気分。
早速 Google で linux コマンドライン 添付ファイル メール 送信を検索。linux-users の記事などがヒット。いくつかスクリプトやコマンドが紹介されていたが、mpack というツールを使うことにした。
[linux-users:83133] Re: sendmailで添付ファイルをつけて送れるか?
http://search.luky.org/linux-users.8/msg03133.html
mpack
ftp://ftp.andrew.cmu.edu/pub/mpack/
メール本文を指定できないとか、いくつか不満はあるがとりあえずはこれでもいい。
#!/bin/sh
tar -C /home/hiroaki/ log.txt chalow-0.20 script public_html/log -Ivcf /home/hiroaki/changelog.tar.bz2 >/dev/null
mpack -s "[ChangeLog Pack] `date`" /home/hiroaki/changelog.tar.bz2 example@example.com
・・・と思ったが、from を指定できないのはダメだな。やはりスクリプトを書かなければならないか・・・。
- 2004-10-09 追記
Ruby 1.8 の標準ライブラリだけで動作する添付ファイル付きメール送信スクリプトを 2004-10-09 に書いた。2003-12-08 に fetchmail + procmail を導入して以来、ログイン時に You have mail と言われるようになった。pro は外部からの smtp を受け付けないし、メールを受け取るような cron も設定していない。いったいどこからメールが来てるんだろう、と不思議に思って調べると、.procmailrc に
ログインしたときに出てる訳だから、ログイン時に実行されるスクリプトあたりだろうか、と推測し、/etc/profile, /etc/bashrc, $HOME/.login, $HOME/.bash_profile, $HOME/.bashrc を調べてみたが、どこにもそれらしきスクリプトは無かった。唯一 /etc/profile に
もうこうなったら Google に聞くしかない。Google で ログイン "you have mail" を検索すると、JM のページがトップでヒット。
Manpage of LOGIN
http://www.linux.or.jp/JM/html/shadow/man1/login.1.html
なるほど、login コマンドそのものが出力していたのか。でも、「メールボックスの状態によって」というのが気になる。どんな状態だとどのメッセージが出るのかはわからなかった。login のソースを読むのが近道かなあ。
:0 cとルールを記述していたため、ローカルのメールボックスにメールを残しつつ転送するようになっていたことが原因だとわかった。どこかのウェブページにあった .procmailrc を、内容を吟味せずにほとんどそのまま使ってしまったので当然の結果だ。
- You have mail って誰が言ってるの?
ところで、You have mail って誰が出してるメッセージなんだろう、と思って調べてみた。ログインしたときに出てる訳だから、ログイン時に実行されるスクリプトあたりだろうか、と推測し、/etc/profile, /etc/bashrc, $HOME/.login, $HOME/.bash_profile, $HOME/.bashrc を調べてみたが、どこにもそれらしきスクリプトは無かった。唯一 /etc/profile に
USER=`id -un`というメールスプールのパスを設定している記述があるだけだ。
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"
もうこうなったら Google に聞くしかない。Google で ログイン "you have mail" を検索すると、JM のページがトップでヒット。
Manpage of LOGIN
http://www.linux.or.jp/JM/html/shadow/man1/login.1.html
ログインに成功すると、システムメッセージやメールの有無が表示される。ログインディレクトリに長さ 0 のファイル .hushlogin を作っておけば、システムメッセージファイルである /etc/motd の表示を無効にできる。メールに関するメッセージは、メールボックスの状態によって "You have new mail.", "You have mail.", "No Mail." のいずれかになる。
なるほど、login コマンドそのものが出力していたのか。でも、「メールボックスの状態によって」というのが気になる。どんな状態だとどのメッセージが出るのかはわからなかった。login のソースを読むのが近道かなあ。
今使っている MUA は NetscapeMessanger 4.8 だ。大学の頃から使い続けている。振り分けや検索などの基本機能はきちんと押さえられており、非常に使いやすい。セキュリティ的にも OutlookExpress よりずっと安心。何より勝手にメールを開いたりしないし。欠点としては、POP アカウントは一つしか登録できないという点だろうか。
fetchmail + procmail を使えば複数サーバのメール一つのアカウントにをまとめられるので、欠点を解消できる。
9時5時ではなく8時から23時というところがエンジニアらしい。
fetchmail + procmail を使えば複数サーバのメール一つのアカウントにをまとめられるので、欠点を解消できる。
- .fetchmailrc
POP ユーザ名が shift_jis のマルチバイト文字という凶悪なアカウントなので、.fetchmailrc は shift_jis で記述した。あんまり各行を精査してないので、冗長な記述があるかも。set postmaster hiroaki
set nobouncemail
defaults
protocol pop3
keep
no mimedecode
smtphost localhost
poll 10.58.30.2
user "私の名前"
password PASSWORD
mda "/usr/bin/procmail"
- .procmailrc
procmail のレシピ。PATH=/usr/bin:/usr/sbin:/usr/ucb:/usr/local/bin:/pub/bin:.
LOGFILE=$HOME/log/procmail.log
:0
* ! ^X-Loop: hiroaki@example.com
! hiroaki@example.com
- cron
# fetch mail
*/5 8-23 * * * /usr/bin/fetchmail -f $HOME/.fetchmailrc 2>&1 >>$HOME/log/fetchmail.log
9時5時ではなく8時から23時というところがエンジニアらしい。
/usr/sbin/sendmail -t saitou-hiroaki@example.com
2004-11-07 追記。どうやら間違ってたみたい。
SENDMAIL(1) sendmail - Postfix Sendmail 互換インターフェース
http://www.kobitosan.net/postfix/jman/sendmail.1.html
-t メッセージヘッダから受信者を抽出します。a
これはコマンドラインで受信者が指定されなかった場合に必要です。