2016-11-18 の日記
「標準課題」というグループ課題で、友達の班に「C言語でメールを送れるようにしたい」という要望があった。おもしろそうだったので、放課後に実験を一緒にやってみた。
構成
学校にはファイアウォールがあってインターネット上のSMTPサーバに直接アクセスすることができないようだったので、とりあえず課題用に配られたRaspberry PiをSMTP・POP3/IMAPサーバとすることにした。Raspberry Piにユーザーアカウントを作り、Maildirにメールが届くようにする。
前提
ユーザーアカウントは事前に作ってあり、ログインできるものとする。なければ useradd -m someone
で作っておく。
Postfixのインストールと設定
Raspbian Jessieを使っていたので、Debian 8での設定手順がそのまま使える。「Debian 8 Jessie : MAILサーバー : Postfix インストール/設定 : Server World」を参考にした。実験用で外に出すつもりがなかったし、時間の余裕があまりなかったので、以下の点は変えた。
- インストール中、構成のプリセットの選択で「ローカルのみ」を選んだ。
- 容量制限やSMTP-Authの設定をしなかった。
SMTPサーバの確認
初めにmailutilsを入れてmailコマンドを使えるようにした。
sudo apt-get install mailutils
また、RaspbianではMAIL環境変数が設定されていなかったようなので、以下の内容で /etc/profile.d/mail.sh を作ってログイン時に設定されるようにした。
export MAIL=$HOME/Maildir
反映させるため、一旦ログアウトして再度ログインする。
続いてsendmailコマンドで自分宛てにメールを送った。
sendmail ocha@example.org # 以下は標準入力 From: ocha@example.org To: ocha@example.org Subject: Hello Hello world! .
送信後、mailコマンドで確認すると、送ったメールが届いていた。
C言語でメールを送るプログラムを作る
sendmailコマンドを呼び出して標準入力に書き込めばメールを送信できたので、popen(3)でそれを行う。エラー対策等は厳密ではないので注意。
/* * send-hello.c */ #include <stdio.h> int main(int argc, char* argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s NAME ADDRESS\n", argv[0]); return 1; } char* name = argv[1]; char* address = argv[2]; char sendmail_command[256]; snprintf(sendmail_command, sizeof(sendmail_command), "sendmail %s", address); FILE* sendmail = popen(sendmail_command, "w"); if (sendmail == NULL) { perror("popen"); return 1; } fputs("From: ocha@example.org\n", sendmail); fprintf(sendmail, "To: %s\n", address); fputs("Subject: Hello\n\n", sendmail); fprintf(sendmail, "Hello, %s!\n", name); fputs(".\n", sendmail); pclose(sendmail); return 0; }
使うときはこのような形で。
./send-hello ocha ocha@example.org
Dovecotのインストールと設定
最後にPOP3/IMAPサーバとしてDovecotをインストールして、メールソフトから受信したメールを見られるようにした。Postfixと同様に「Debian 8 Jessie : MAILサーバー : Dovecot インストール/設定 : Server World」を参考にした。
PCのThunderbirdでIMAPサーバとしてRaspberry PiのIPアドレスとポート番号143を指定して、上のプログラムを使って送信したメールを受信できることを確認した。
感想
調べながら作業を行ったので時間がかかったが、要点を押さえればそれほど複雑ではない印象だった。
sendmailコマンドはなかなか便利。ちょうど学校でプロセス関連のシステムコールやライブラリ関数の使い方を習った後だったので、良い応用例だった。Raspberry Piなら、ハードウェアの制御と合わせればおもしろいものができそう。