Amazon SESとAWS SDK for PHP2を使ってPHPでメールを送信する方法


Amazon SES

PHPからメール送信したいシーンは多くあると思いますが、AWSのAmazon SES(Simple Email Service)というメール配信用サービスを使用する方法があります

AWSが提供している開発キット「AWS SDK for PHP2」を使いメールを送信するサンプルコードを、添付ファイルが無い場合とある場合それぞれについてメモします。

事前準備

Amazon SESおよびAWS SDK for PHP 2を使うにはいくつか事前準備が必要です。

Amazon SESを使用するための事前準備

Amazon SESを使うためには以下のような準備が必要になります。

  • 送信元として使用するメールアドレスの確認
  • IAM(Identity and Access Management)でメール送信用のAWSユーザを作成
  • IAMユーザのアクセスキー・シークレットキーの取得

準備の方法は以前書いた、iOSからAmazon SESを使ってメール送信するための以下のエントリに記載のものと同様です。

関連エントリ:Amazon SESとAWS SDK for iOSを使ってiPhoneからメールを送信する方法

また2014年7月現在、Amazon SESは以下のリージョンでのみ使用可能です。

  • US East (N. Virginia)
  • US West (Oregon)
  • EU (Ireland)

AWS SDK for PHP 2を使用する事前準備

AWS SDK for PHP 2を使用するにはAWS公式サイトよりSDKaws.pharをダウンロードし、PHPでインクルードできる状態にしておきます。

AWS SDK for PHP 2を使用したコーディングサンプル

メール送信のサンプルコードです。添付ファイルが無い場合とある場合それぞれについて記載します。

テキストメールまたはHTMLメールを送信する場合

通常のテキストメールまたはHTMLメールはsendEmail()メソッドを使用することで送信可能です。

<?php
// AWS SDK for PHP 2を読み込む
require_once './aws.phar';

use Aws\Ses\SesClient as SesClient;
use Aws\Common\Enum\Region as Region;
use Aws\Ses\Exception\SesException as SesException;

$aws_access_key = "YOUR_ACCESS_KEY";    // アクセスキー
$aws_secret_key = "YOUR_SECRET_KEY";    // シークレットキー

$source = 'you@example.com';    //送信元アドレス
$dest = 'you@example.com';    //送信先アドレス
$charset = 'ISO-2022-JP';   //変換先の文字コード

$subject = "SESサンプルメール";     //件名
$body_text = "サンプルメールです。\n\nPHP+Amazon SESで送信されました。";    //本文

try {
    //アクセスキー、シークレットキー、リージョンを指定しクライアントを生成する
    $client = SesClient::factory(
                    array(
                        'key' => $aws_access_key,
                        'secret' => $aws_secret_key,
                        'region' => Region::OREGON
                    )
    );

    //添付ファイル無しのメールを送信
    $result = $client->sendEmail(array(
        // Source(送信元)は必須
        'Source' => $source,
        // Destination(宛先)は必須
        'Destination' => array(
            'ToAddresses' => array($dest), // To
            'CcAddresses' => array(), // CC(あれば)
            'BccAddresses' => array(), // BCC(あれば)
        ),
        // Message(メッセージ部分)は必須
        'Message' => array(
            // Subject(件名)は必須
            'Subject' => array(
                // Data(件名部分データ)は必須
                'Data' => $subject,
                'Charset' => $charset,
            ),
            // Body(本文)は必須
            'Body' => array(
                'Text' => array(
                    // Data(本文データ)は必須
                    'Data' => $body_text,
                    'Charset' => $charset,
                ),
            /* HTMLメールを送る場合
              'Html' => array(
              // Data(HTMLデータ)は必須
              'Data' => 'HTMLです',
              'Charset' => $charset,
              ),
             */
            ),
        ),
            )
    );

    // 結果を表示
    echo '<pre>';
    print_r($result);
    echo '</pre>';
    
} catch (SesException $exc) {
    echo $exc->getMessage();
}

メール送信の流れは以下のような感じです。

  • Amazon SESのクライアントインスタンスを生成
  • 送信先・本文などの内容を引数に指定しsendEmail()メソッドを実行

実際に送信されたメールは以下の画像のようなイメージです。
Amazon SES PHP テキストメール

添付ファイル付きメールを送信する場合

添付ファイル付きメールはsendRawEmail()メソッドを使用することで送信可能です。


<?php
// AWS SDK for PHP 2を読み込む
require_once './aws.phar';

use Aws\Ses\SesClient as SesClient;
use Aws\Common\Enum\Region as Region;
use Aws\Ses\Exception\SesException as SesException;

// 言語と文字エンコーディングをセット
mb_language("Japanese");
mb_internal_encoding("UTF-8");

$aws_access_key = "YOUR_ACCESS_KEY";    // アクセスキー
$aws_secret_key = "YOUR_SECRET_KEY";    // シークレットキー

$source = 'you@example.com';    //送信元アドレス
$dest = 'you@example.com';    //送信先アドレス
$charset = 'ISO-2022-JP';   //変換先の文字コード

$subject = "SESサンプルメール";     //件名
$body_text = "サンプルメールです。\n\nPHP+Amazon SESで送信されました。";    //本文

$filepath = "./images/sample.jpg";  //添付するファイルのパス

try {
    // アクセスキー、シークレットキー、リージョンを指定しクライアントを生成する
    $client = SesClient::factory(
                    array(
                        'key' => $aws_access_key,
                        'secret' => $aws_secret_key,
                        'region' => Region::OREGON
                    )
    );

    // パートの境界を表す文字列(boundary)
    $boundary = "Boundary_(PHP_SES/" . uniqid(rand()) . ")";

    $finfo = finfo_open(FILEINFO_MIME_TYPE);

    $path_parts = pathinfo($filepath);
    $filename = $path_parts['basename'];        //ファイルパスからファイル名を取得
    $mimetype = finfo_file($finfo, $filename);  //ファイルからMIMEタイプを取得

    $subject = str_replace("\r", "", mb_encode_mimeheader($subject));

    // 本文の文字コードを指定したものにエンコーディングする
    $body_text = mb_convert_encoding($body_text, $charset);
    // 添付するファイルを読み込んでBase64エンコードする
    $attachment_data = base64_encode(file_get_contents($filepath));

    // rawメッセージ部分
    $message = "To: " . $dest . "\n";
    $message.= "From: " . $source . "\n";
    $message.= "Subject: " . $subject = str_replace("\r", "", $subject) . "\n";
    $message.= "MIME-Version: 1.0\n";
    $message.= 'Content-Type: multipart/mixed; boundary="' . $boundary . '"';
    $message.= "\n\n";
    $message.= "--" . $boundary . "\n";
    $message.= 'Content-Type: text/plain; charset=' . $charset;
    $message.= "\n";
    $message.= "Content-Transfer-Encoding: 7bit\n";
    $message.= "Content-Disposition: inline\n";
    $message.= "\n";
    $message.= $body_text; //本文をISO-2022-JPに変換
    $message.= "\n\n";
    $message.= "--" . $boundary . "\n";
    $message.= 'Content-Type: ' . $mimetype . '; name="' . $filename . '"';
    $message.= "\n";
    $message.= "Content-Transfer-Encoding: base64\n";
    $message.= 'Content-Disposition: attachment; filename="' . $filename . '"';
    $message.= "\n";
    $message.= $attachment_data;
    $message.= "\n";
    $message.= "--" . $boundary . "\n";

    // SESクライアントからRawメールを送信する
    $result = $client->sendRawEmail(array(
        'Source' => $source,
        'Destinations' => array($dest),
        // RawMessage is required
        'RawMessage' => array(
            // Data is required
            'Data' => base64_encode($message),
        ),
    ));

    // 結果を表示
    echo '<pre>';
    print_r($result);
    echo '</pre>';
    
} catch (SesException $exc) {
    echo $exc->getMessage();
}

メール送信の流れは以下のような感じです。sendEmail()でテキストのみを送信する場合と異なり、メッセージ部分にはmultipart/mixedで複数のパートを格納するメッセージを指定する必要があるのがポイントです。

  • Amazon SESのクライアントインスタンスを生成
  • 複数のパートを格納するメッセージ部分の文字列を作成
  • 送信先・メッセージ部分などの内容を引数に指定しsendRawEmail()メソッドを実行

マルチパート形式のメッセージについては以下のサイトが参考になりました。

関連サイト:メールヘッダー。~ファイルを添付したらどうなるの?~ | Opentone Labs.

実際に送信されたメールは以下の画像のようなイメージです。ちゃんと画像が添付されています。
Amazon SES PHP マルチパートメール

おわりに

以前のエントリではAmazon SES + iOSからのメール送信を実装しましたが、実際に使う場面としてはPHPのほうが多いのではないでしょうか。

自分でSMTPサーバを用意しなくても簡単にメールが送信できるのは開発者にとっては嬉しいと思いました。