Laravelでメール(IMAP)を受信して添付ファイルを抽出する

はじめに

メールを定期的に受信して、添付ファイルを自動的に保存するという仕組みを作りたくて調べてみました。

できそうな方法

AWSのSES

AWSのメールサービスSESを使ってできそう。受信したメールをS3へ保存する機能があり、それをトリガーとしてLambdaを起動。Lambda関数でメールデータを取得して添付ファイルを抽出し再びS3へ保存。

MicrosoftのPower Automate

Microsoftのいろいろ自動化ツール。メールを自動受信して添付ファイルを各種クラウドサービスへ保存する機能がある。

Gmail

柔軟な拡張性を持ったメールサービス。単体ではなく各種サービスと連携して色々な操作ができそう。

自作

ライブラリなどを使えば比較的簡単にメールサーバにアクセスできる。様々な操作や添付ファイル抽出もできたりする。

自作を選択

SESPower Automateを使った方法は月々のコストがかかるので今回はスルー。Gmailでいろいろしようと思ったけど、laravel-imapというLaravelのライブラリを見つけたので、Laravel使いの自分としてはこちらを選択。

laravel-imapの使い方

laravel-imapphp-imapのLaravel仕様。php-imapはPHPの拡張モジュールであるIMAPを独自にパッケージ化したライブラリー。(なのでPHPのIMAP拡張モジュールがサーバに入ってなくてもOK)

インストール

laravel-imapは、サーバーに以下の2つのモジュールが入っていることが必須。

  • mbstring
  • mcrypt

ただ、mcryptはPHP7.2から非推奨(削除)となっています。

これを踏まえた上で使用したい場合は、読み進めてください😅

レンタルサーバ(XSERVER、さくらレンタルサーバ)の場合はどちらも有効になっていますが、VPSやクラウド、開発環境では有効になっているか確認してください。

自分の環境では、mcryptがなくても使えました。なんで?

ちなみにDockerで開発環境を作っている場合は、Dockerfileに以下のように書くとmcryptが有効になります。

RUN apt-get -y install \
    libmcrypt-dev \
    && pecl install mcrypt-1.0.4

それとphp.iniファイルに

 extension=mcrypt.so

を追記。

laravel-imapをインストール

環境が整ったらインストールします。すでにLaravelはインストールされている前提です。Composerでインストールします。

$ composer require webklex/laravel-imap

設定ファイルをconfig/内に設置します。

$ php artisan vendor:publish --provider="Webklex\IMAP\Providers\LaravelServiceProvider"

設定

.envファイルにメールサーバの情報を追記します。

IMAP_HOST=somehost.com
IMAP_PORT=993
IMAP_ENCRYPTION=ssl
IMAP_VALIDATE_CERT=true
IMAP_USERNAME=root@example.com
IMAP_PASSWORD=secret
IMAP_DEFAULT_ACCOUNT=default
IMAP_PROTOCOL=imap

先程設置したconfig/imap.phpでメールアカウントの設定などできます。(しなくても.envの情報で取得できます)

添付ファイル取得・保存

例えば、Controllerで使う場合。

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Storage;
use Webklex\IMAP\Facades\Client;

class ImapMailController extends Controller
{
    public function index()
    {
        $client = Client::account('default'); // config/imap.phpで設定しているdefaultアカウント(.envの設定)を使用
        $client->connect();

        $folder = $client->getFolderByName('INBOX'); // フォルダ名を指定して取得(受信BOXはだいたいINBOX)

        // メッセージ取得(フィルター)
        $messages = $folder->messages()
            ->from('hoge@example.com') // 特定のメールアドレスからのみ
            ->setFetchOrder('desc') // 新しい順、ascで古い順
            ->limit($limit = 100, $page = 1) // 取得数を制限(1ページ辺り100件、1ページ目を取得)
            ->get();

        foreach ($messages as $message) {

            if ($message->hasAttachments()) { // 添付ファイルがあるかどうか

                // 添付ファイル保存
                foreach ($message->getAttachments() as $attachment) {
                    Storage::put('path/' . $attachment->name, $attachment->content);
                }
            }
        }
        return;
    }
}

こんな感じで取得、保存できる。

その他の機能

メール情報の取得

// ヘッダー取得
$message->getHeader();

// タイトル取得
$message->getSubject();

// 添付ファイル数取得
$message->getAttachments()->count();

// 本文(テキスト)の取得
$message->getTextBody();

// 本文(HTML)の取得
$message->getHTMLBody();

// 解析前の生メールを取得
$message->getRawBody();

他にも、メールのコピーや移動、削除とか、フォルダやフラグ操作など色々できます。詳しくは、PHP-IMAPのドキュメント参照

まとめ

ライブラリを使うと簡単にメール操作できるんですね。いろいろ自動化ツールの開発には便利なんじゃないでしょうか。

ちなみにGmailのメールを取得する場合の.envは、以下の通り。

IMAP_HOST=imap.gmail.com
IMAP_PORT=993
IMAP_ENCRYPTION=ssl
IMAP_VALIDATE_CERT=false
IMAP_USERNAME=username@gmail.com
IMAP_PASSWORD=password # ←アプリパスワード
IMAP_DEFAULT_ACCOUNT=default
IMAP_PROTOCOL=imap

Gmailのメールサーバへ接続するには、Gmail側(Googleアカウント)の設定で2段階認証の有効化アプリパスワードの発行をする必要があります。アプリパスワードの設定は2段階認証を有効化するとメニューに現れます。