yamlを編集するだけで設定できて、
自由にメールの内容を変更できるメーリングリストサーバが
欲しくなったので作ってみました。
作ったといっても30行もないrubyスクリプトです。
https://github.com/yaasita/ymst
目次
これは何?
こんな感じのyamlを書けばメーリングリストを作れるってやつです
mltest1@ml.example.com: - member1@example.com - member2@example.com - member3@example.com mltest2@ml.example.com: - member4@example.com - member5@example.com - member6@example.com
mltest1@ml.example.comに送れば
member1@example.com
member2@example.com
member3@example.com
に届くという意味です
これだけならaliasesでもできるんですが、yamlの方が個人的にすきなのと、
今後、あて先ごとに名前等の付加情報もつける可能性があるので、yamlにしました。
仕組み
- メールをpostfixが受けてvirtual_alias_mapsによりymstユーザに集約します。これによりどんなアドレスでもymst@localhostに届くようになります。
- ymst.shがプログラムを起動します。直接send.rbに送ってもいいのですが、rbenv,rvmとか使いたい人やPATHを変えたい、シェルコマンドを使いたい、テストしやすくしたい等の需要がありそうなので、一個シェルスクリプトを挟みました。
- send.rbでメールを加工して、yamlに基づいて会員に送信しています。sendmailコマンドに標準出力経由で渡しています。
- sendmailで渡されたメールをpostfixが処理し、会員のアドレスに配送します。
使い方
サーバ設定はansibleに書いておきました。
設定方法は
READMEに書いたとおりですが
簡単に説明しておきます
以下のファイルを編集してください
* ansible/roles/ymst/files/authorized_keys: 自分の公開鍵にする * ansible/ansible_hosts: 対象のサーバのアドレス、ユーザ名、パスワード * ansible/group_vars/all: メーリングリストのドメインを設定する
ansibleについて分る人は適宜環境に合わせて編集してください
実行します
cd ansible ansible-playbook site.yml
これでサーバは準備できました。
以降はサーバにあるmail.ymlファイルを変更すればOKです。
サーバのリポジトリはgit hookによってworktreeもリセットされるようになっています。
なのでそのままpushすればOKです
git clone ymst@yourserver.eample.com:ymst cd ymst vi mail.yml git add mail.yml && git commit -m "mod ml" && git push
※メーリングリストの中にメーリングリストを入れてもループはしませんが、エラーになります
カスタマイズ
設定ファイルは一切無いので直接rubyのコードを編集して下さいw
とだけ言うのもあれなのでメールからコマンドに渡したときの挙動やら注意点やらを書いておきます
メールをコマンドへ渡す
今回は以下のファイルによって
/home/ymst/.forward
内容は以下の通り
"|/home/ymst/ymst/bin/ymst.sh"
コマンドへ渡す方法はpostfixのmapファイルや/etc/aliasesでも可能です。
このコマンドはメールを同時に受信すれば平行して走る可能性もあります。
なので、一時ファイルを作る場合メールファイルを作る場合はファイル名のバッティングに注意して下さい
ローカル配送をする場合は maildrop等を利用すると便利です
入力の受け取り方
メールの内容は標準入力によって渡されます
例えば以下のようにすると
/tmp/mail.pidでメールが保存されます
#!/bin/bash cat - > /tmp/mail.$$
作成されるファイルのデフォルトのパーミッションは
600なので他のユーザが見る場合は注意します
ls -l 合計 4 -rw------- 1 ymst ymst 379 8月 1 13:31 mail.5744
環境変数について
以下の環境変数が設定されます
よく使うのはenvelope-fromをあらわすSENDER
envlope-toをあらわすORIGINAL_RECIPIENT
接続してきたクライアントのIPをあらわすCLIENT_ADDRESSくらいでしょうか
USER=ymst HOME=/home/ymst DOMAIN=localhost LOGNAME=ymst CLIENT_PROTOCOL=SMTP ORIGINAL_RECIPIENT=mltest2@ml.example.com LOCAL=ymst PATH=/usr/bin:/bin SENDER=from@hoge.example.com LANG=C CLIENT_ADDRESS=192.168.33.1 SHELL=/bin/bash MAIL_CONFIG=/etc/postfix PWD=/var/spool/postfix RECIPIENT=ymst@localhost CLIENT_HOSTNAME=unknown CLIENT_HELO=sender.bpsinc.jp
終了コードについて
プログラムの終了コードについて
よく使うものだけ紹介します
<
h4 class="article" id="exit0"> exit 0
終了コードがゼロなら問題なく配送したとして、処理を終了させます
以下の例だと問題なく受け取るけどそのまま捨てます
送信者はエラーになったことは分りません
<
h4 class="article" id="exit69"> exit 69
メールをバウンスさせます。
バウンスなのでエラーだったことを送信元に知らせます。(bounceメール)
後方散乱メールに利用されないように注意してください
(ちなみにexit 1とかexit 2でもこの挙動になります)
無効なアドレスに来たメールをバウンスさせる例
送信者に届くbounceメール
This is the mail system at host ml.example.com. I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below. For further assistance, please send mail to postmaster. If you do so, please include this problem report. You can delete your own text from the attached returned message. The mail system <ymst@localhost> (expanded from <mltest1@ml.example.com>): service unavailable. Command output: address not found
<
h4 class="article" id="exit75"> exit 75
defferさせます。
defferは一時的に配送を中止して、キューにためておき、しばらくしたら再送してくれることです。
以下の例はmail.ymlが無い場合に一時的に配送を中止する例
mailqコマンドでみるとキューに溜まっているのが確認できます
-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient------- 3E661140446 240 Fri Aug 1 15:24:22 from@hoge.example.com (temporary failure) ymst@localhost -- 0 Kbytes in 1 Request.
カスタマイズ例
とりあえず必要になった変更例だけ箇条書きしておきます
enbelove from変更する
sendmail の -f オプションで出来ます
Gmail等の外部送信メールサーバを使用したい
postfixの設定でいけます
詳しくはその他のサイトに解説があると思います
送信するアドレス別にトラッキングコードつける
こんな感じに送信先に応じてURLを変える
http://www.example.com/?q=5ee5c2eecf82f58b0798183da83d6997de5cf363
特定のIP、特定のFromからじゃなければ受け付けない
postfixでもできますが、今回はbashで
smtp auth等はpostfix側でします
特定のヘッダを削除したい
receivedヘッダ等は消しておく
以上です