PHPでメールを送受信するアプリを作った

OhLifeというWebサービスがある。メールの送受信をフックとしたログ記録サービスで、以下のような特徴がある。

  • 1日1回、決まった時間にメールを送ってくる
  • このメールに返信すると、返信内容が記録される
  • OhLifeが送ってくるメールの本文には、過去のログが含まれる

OhLifeの主な機能には満足しているのだけど、一点だけ不満がある。それは、過去のログの選ばれる規則を設定できないこと。個人的な用途としては、前日からの進捗確認に使いたいので、必ず昨日のログを表示してほしい。しかし、OhLifeの過去ログ抽出規則は、「前日・1週間前・1ヶ月前」等があり、古いものが優先されているように思える。

類似サービスも探したのだが、どうも無いみたい。

無いなら作ろう。

ということで、作ってみた(現在、一般公開はしていない)。

サーバはさくらVPSで、OSはDebian Wheezy。メールサーバとしてはPostfixを使用。今回一番ハマったのはPostfixの設定だったり。

Postfixで受け取ったメールをPHPスクリプトに渡す方法としては、
この記事が参考になる。

また、メールをパースする方法としては、ライブラリを使用することにした。最初は
illuminate/mailなども検討したのだけど、サンプルコードが探しやすかったので
PEAR::Mail_MimeDecodeにした(サンプルコードは
この記事を参考にした)。

インストールはComposerで。

{
"repositories": [
{
"type": "pear",
"url": "http://pear.php.net/"
}
],
"require": {
"pear-pear.php.net/Mail_mimeDecode" : "*"
}
}

メールを受信するプログラムはこんな感じ(受け取ったメールの本文をDBに保存する)。

<?php
require_once __DIR__ . '/vendor/autoload.php';
$raw_mail = file_get_contents('php://stdin'); // メール本文を標準入力から受け取る
$params = [];
$params['include_bodies'] = true;
$params['decode_bodies']  = true;
$params['decode_headers'] = true;
$params['input'] = $raw_mail;
$params['crlf'] = 'rn';
$mail_data    = Mail_mimeDecode::decode($params);
$mail_address = $mail_data->headers['from'];
$mail_address = trim(substr($mail_address, strpos($mail_address, '<')), '<>');
$charset      = $mail_data->ctype_parameters['charset'];
$mail_body    = mb_convert_encoding($mail_data->body, 'UTF-8', $charset);
try {
$dbh = require_once __DIR__ . '/db_connection.php'; // PDOオブジェクトを取得
// メールアドレスからユーザーを取得
$sql = 'SELECT * FROM users WHERE mail = :mail';
$stmt = $dbh->prepare($sql);
$result = $stmt->execute([':mail' => $mail_address]);
// DBにメール本文を保存
if (true === $result) {
$row = $stmt->fetchAll(PDO::FETCH_ASSOC)[0];
$sql = 'INSERT INTO logs (users_id, body, created_at) VALUES (:users_id, :body, :created_at)';
$stmt = $dbh->prepare($sql);
$stmt->bindParam('users_id', $row['id']);
$stmt->bindParam('body', $mail_body);
$stmt->bindParam('created_at', date('Y-m-d H:i:s'));
$stmt->execute();
}
} catch (Exception $e) {
error_log($e->getMessage() . PHP_EOL, 3, __DIR__ . '/log/receiver.log');
exit(1);
}

メール送信機能はmb_send_mail()使えば簡単。あとは、cronにメール送信スクリプトを登録して、定期実行すればOK。

コメントを残す

コメントを残す