AWS SDK for PHP を利用してSESで添付ファイル付きのメールを送信する

こんにちは 👋

エキサイトホールディングス Advent Calendar 2021の3日目は、エキサイト株式会社の伊藤(🐦 @motokiito2)が担当させていただきます!

今回は、AWS SDK for PHP を利用して、SESで添付ファイル付きのメールを送信する方法について書かせていただきたいと思います!

なお、SDKの導入や SesClient() の利用方法については本記事では割愛させていただきます。

添付ファイルつきメールを送信する方法

AWS公式のチュートリアルで利用されている sendEmail() は宛先、送信元、本文、件名、文字コード等を渡すだけでメールを送信することができます。

しかし、 sendEmail() には添付ファイルを指定するパラメータが存在しないため、メールのheaderとbodyを自分で成形して送信する sendRawEmail() を利用する必要があります。

docs.aws.amazon.com

sendRawEmail() の利用

sendRawEmail()sendEmail() とは異なり、メールヘッダおよびコンテンツを自前で整形して渡す必要があります。

この例では、送信元 $from , 宛先 $to を渡していますが、必須パラメータは RawMessageのみなので、RawMessageのヘッダ内に含めても問題ないです。

<?php

$this->sesClient->sendRawEmail([
    'Destinations' => [
        $values['to'],
    ],
    'Source'     => $values['from'],
    'RawMessage' => [
        'Data' => $rawMessage,
    ],
]);

sendRawEmail() の詳細は下記ドキュメントを参照してください。

https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-email-2010-12-01.html#sendrawemail

RawMessage

RawMessageを用意する方法はいろいろありますが、この例ではシンプルに文字列で用意します。

SESの設定セットを利用している場合は、ヘッダー部に X-SES-CONFIGURATION-SET: を含める必要があります。

また、sendEmail() がよしなにやってくれている部分を自前で用意する必要があるので、注意してください。

  • SubjectのMIMEエンコードを忘れない

  • 添付ファイルを入れる場合にはメッセージの Content-type を multipart/mixed にしておく必要がある

など..

<?php

private function generateRawMessage(
    string $from,
    string $to,
    string $subject,
    string $body,
    string $fileName,
    string $fileStringBase64Encoded
) : string {
    $boundaryString = '__BOUNDARY__';

    return 'To: ' . $to . "\n"
         . 'From: ' . $from . "\n"
         . 'X-SES-CONFIGURATION-SET: ' . $this->config['aws']['ses']['configuration_set'] . "\n"
         . 'Subject: ' . mb_encode_mimeheader($subject, 'UTF-8') . "\n"
         . "MIME-Version: 1.0\n"
         . 'Content-Type: multipart/mixed; boundary="' . $boundaryString . '"' . "\n\n"
         . '--' . $boundaryString . "\n"
         . "Content-Type: text/html; charset=\"UTF-8\"\n\n"
         . nl2br($body) . "\n\n"
         . '--' . $boundaryString . "\n"
         . 'Content-Type: application/octet-stream; name="' . $fileName . '"' . "\n"
         . "Content-Transfer-Encoding: base64\n"
         . 'Content-Disposition: attachment; filename="' . $fileName . '"' . "\n\n"
         . $fileStringBase64Encoded
         . '--' . $boundaryString . "\n";
}

添付ファイル

添付ファイルは、ファイルをbase64エンコードした文字列を用意します。

<?php

private function generateFileStringBase64Encoded(
    string $fileAbsolutePath
) : string {
    if (!file_exists($fileAbsolutePath)) {
        return false;
    }

    return chunk_split(base64_encode(file_get_contents($fileAbsolutePath)));
}

メール送信メソッドサンプル

これまでの実装を利用した送信メソッドのサンプルコードをのせます。 (SesClientとLoggerはクラス内でコンストラクタインジェクションしています)

<?php

private function sendEmailWithAttachment(
    string $from,
    string $to,
    string $subject,
    string $messageBody,
    string $fileAbsolutePath,
    string $fileName
) : void {
    $fileStringBase64Encoded = $this->generateFileStringBase64Encoded($fileAbsolutePath);

    if (!$fileStringBase64Encoded) {
        throw MailSendFailedException::factoryMailSendFailedException('attachment file is invalid');
    }

    $rawMessage = $this->generateRawMessage(
        $from,
        $to,
        $subject,
        $messageBody,
        $fileName,
        $fileStringBase64Encoded
    );

    try {
        $result = $this->sesClient->sendRawEmail([
            'Destinations' => [
                $to,
            ],
            'Source'     => $from,
            'RawMessage' => [
                'Data' => $rawMessage,
            ],
        ]);
        $messageId = $result['MessageId'];
        $this->logger->info("Completed to sent, messageId: $messageId");
    } catch (AwsException $e) {
        $this->logger->error('[MailSendError] ErrorMessage: ' . $e->getMessage());

        throw MailSendFailedException::factoryMailSendFailedException('mail send error');
    }
}

最後に

AWS SDK for PHPの SesClientは、シンプルなメールを送信する場合は実装が楽なのですが、メールヘッダを弄る必要があったり、今回のようにファイルを添付したい場合などはRawMessageを扱う必要があり、実装が少し複雑になります。

同じようなケースで sendRawEmail() を利用しなければいけない場合に、この記事が参考になってくれればとても嬉しいです!


弊社アドベントカレンダーの他の記事も是非!

qiita.com