nanisore oishisou

Webエンジニアあるまさんのゆるふわ奮闘記。

PHPでメール着弾時、メール本文をパースしDBへ格納する(2)〜メールパース編〜

2年前に、私はこんなことを言っていた。

次回は、PHPをキックしてメールをパースしてDBに格納するよっ♥
お楽しみにね★

その次回が、令和という元号が発表された節目の日になろうとは、私も読者も思っていなかっただろう。
びっくり!

この作業について、これからも聞かれると思うのでまとめておきます。

おさらい

とあるメールアドレス(chakudan@example.com)にメールを送信すると
Laravelでつくったstore_emailというコマンドが叩かれて、
メールの内容をDBに格納してくれるという、メール内容データDB取り込みの機構を構築する。

まずは、メールサーバを構築し、着弾用ユーザをつくり、
そのユーザにメールが届いた際に別のアドレスに転送できるようにサーバを設定するというところまでが
前回の作業だった。

arm4.hatenablog.com

今回は、その次のPHPをキックしてDBに格納するところまでをまとめる。

やること

  • Laravelでstore_emailコマンドを作成
  • /etc/aliasesでメール受信時にstore_emailが叩かれるよう設定
  • phpにmailparseモジュールを追加
  • php-mime-mail-parserをinstall
  • メールをパースしてDBに格納する

Laravelでstore_emailコマンドを作成

まずはメール送信時に、そのコマンドが本当に叩かれるかどうかというのを確かめたいので、 ログを吐き出すだけのコマンドを作成する。

.env

MAIL_DRIVER=sendmail

コマンドを作成

php artisan make:command StoreEmail

*古いバージョンのLaravelをお使いの方はmake:commandではなくmake:consoleになる。

app/Console/Commands/StoreEmail.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use \Log;

class StoreEmail extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:store_email';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'メールをDBに保存するコマンド';
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        Log::info('メールを受信しました。');
    }
}

/etc/aliasesでメール受信時にstore_emailが叩かれるよう設定

chakudan@example.comにメールを送ったら、chakudanユーザのメールボックスにメールが届き、
さらにstore_emailコマンドがキックされるように、/etc/aliasesのchakudanユーザの箇所を以下のようにしておく

sudo vi /etc/aliases

/etc/aliases

chakudan: chakudan, "| /usr/bin/php /var/www/hogehoge/artisan command:store_email"

chakudai@example.comにメールを送信したら、ログに「メールを受信しました。」が記載されていたら メール送信&PHPキックが成功している。

phpにmailparseモジュールを追加

php-mime-mail-parserというライブラリを使ってメールのパースを行おうと思うが、 インストールするにはmailparseモジュールをphpに追加する必要がある。

cd /tmp
pecl download mailparse
tar xvzf mailparse-3.0.2.tgz
cd mailparse-3.0.2
phpize
./configure
sed -i 's/^\(#error .* the mbstring extension!\)/\/\/\1/' mailparse.c
make
make install
echo "extension=mailparse.so" > /etc/php.d/30-mailparse.ini
httpd -k graceful

mailparseのモジュールがちゃんと入ってるか確認する

php -i| grep mailparse

mailparse
mailparse support => enabled
mailparse.def_charset => us-ascii => us-ascii

php-mime-mail-parserをinstall

php-mime-mail-parserというライブラリをinstallする。

composer require php-mime-mail-parser/php-mime-mail-parser

メールをパースしてDBに格納する

app/Console/Commands/StoreEmail.php

<?php


use PhpMimeMailParser\Parser;
use App\Inquiry;

    public function handle()
    {
        Log::info('メールを受信しました。');

        $parser = new Parser();
        $parser->setStream(fopen('php://stdin', 'r'));

        $to = $parser->getHeader('to');
        $addressesTo = $parser->getAddresses('to');
        $from = $parser->getHeader('from');
        $addressesFrom = $parser->getAddresses('from');
        $subject = $parser->getHeader('subject');
        $body = $parser->getMessageBody('text');
        $text_arr = explode("\n", $body);

        // ↓こんな感じでデータが取得できる
        
        // $from = 'example@example.co.jp';
        // $subject = '◯◯システムお問い合わせ';
        // $text_arr = [
        //     "◯◯システムWebサイトからお問い合わせがありました。\n",
        //     "\n",
        //     "--\n",
        //     "お問い合わせ番号: 0000000203\n",
        //     "氏名(漢字): 山田 太郎\n",
        //     "氏名(カタカナ): ヤマダ タロウ\n",
        //     "性別: 男\n",
        //     "年齢: 32歳\n",
        //     "お電話番号: 03-1234-5678\n",
        //     "メールアドレス: hogehoge@example.com\n",
        //     "お問い合わせ内容:\n",
        //     "商品について質問があります。\n",
        //     "よろしくお願いします。\n",
        //     "--\n",
        //     "\n",
        //     "※このメールは◯◯システムのお問い合わせフォームから送信され\n",
        //     "ました\n",
        //     "\n",
        //     "\n",
        // ];

        Inquiry::create([
            'subject' => $subject,
            'body' => $body,
            'from' => $from,
        ]);
    }

詳しくはphp-mime-mail-parserのgithubページに使い方が書いてあるので、
そちらを参照してみてください。

github.com

あとがき

どうでしたでしょうか、二年越しの私のメールパース編。

メール送信してデバッグして、修正して送信してとかやるのが結構たいへんなので、 Laravel5.7.7以上ならメールパースのデバッグはLaravel Telescopeを使ったほうがいいのでは、と思います。

laravel.com

次のブログは令和元年になるかなーw

次の時代で会おうねー!!!!!!