読者です 読者をやめる 読者になる 読者になる

ochalog

Ruby と MediaWiki が好きな電子・情報系の学生のブログ。

2016-11-18 の日記

「標準課題」というグループ課題で、友達の班に「C言語でメールを送れるようにしたい」という要望があった。おもしろそうだったので、放課後に実験を一緒にやってみた。

構成

学校にはファイアウォールがあってインターネット上のSMTPサーバに直接アクセスすることができないようだったので、とりあえず課題用に配られたRaspberry PiSMTPPOP3/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のThunderbirdIMAPサーバとしてRaspberry PiIPアドレスとポート番号143を指定して、上のプログラムを使って送信したメールを受信できることを確認した。

感想

調べながら作業を行ったので時間がかかったが、要点を押さえればそれほど複雑ではない印象だった。

sendmailコマンドはなかなか便利。ちょうど学校でプロセス関連のシステムコールやライブラリ関数の使い方を習った後だったので、良い応用例だった。Raspberry Piなら、ハードウェアの制御と合わせればおもしろいものができそう。