SendGrid でそれなりの量のメールを送信するメモ

同じ文面だけど、本文に名前が入れたいといった事をすると、同じ文面のメールを送るだけのはずが人数分のメールを送る事になっちゃいます。で、それをどうにかしつつ、SendGridを使って送信するメモ。

Web API v3 使ってます。

# 大量配信のあれこれ

基本的に大量送信用に作られているので、本文は同じだけどユーザ毎で異なる部分をどうにかする方法のメモ書き。

# sendgridの機能

大量送信などに対応するための機能がある。

1. Personalization
	2. 送信先などに関する送るメール文面のメタ情報、recipients, subject, headers, substitutions そしてカスタムargumentsを、配列にした情報
	3. 今回はこれを利用する
4. `SMTPAPI`と`Web API v2`と`Web API v3`
	5. 今回は `Web API v3` を使う。
	6. composer で入れちゃったのが理由。
	7. [SendGrid側でUTF-8処理のバグがあった](https://support.sendgrid.kke.co.jp/hc/ja/articles/206231901-Web-API-v2とv3どちらを利用すべきでしょうか-)っぽいけど、多分もう大丈夫じゃない。わからないけど。

## Personalization 機能

see: https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/personalizations.html

何か Web API v3 からの機能っぽい。

今回は `to`,`subject`,`substitutions` を使う。他にも`custom_args`,`send_at`,`headers`,`cc`,`bcc`が指定できる。

`to`も複数指定できるので、同じ文面の場合は`to`にメールアドレスをひたすら追加して送る形になる。

> 1回のAPI Call につき`to`,`bcc`,`cc`の最大件数ってあるのかしら…？

`指定可能な宛先数は1000件以内です。これには、to, cc, bccパラメータで指定したものを含み、personalizations配列を超えてカウントされます`、と書かれているので、一度に送れる送り先は1000件だそうです。　[制限事項](https://sendgrid.kke.co.jp/docs/API_Reference/Web_API_v3/Mail/index.html#-Limitations)


### 注意点

1. `Personalization` は1回のAPIリクエストに最大1000件が限度なので、1000件以上になる場合は1000件単位で分割して送るしかない: https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/personalizations.html


## Substitution を使う

今回は名前の部分が違い、他の文面で違いがないので、その部分を対応する為の機能。

例えば、メールの本文に `%name%` と仕込み、`SendGrid` の `Personalization`に入れてやれば都合よく`SendGrid`が置換してくれます。

### 注意点

1. `%first name%` など中にスペースを挟むと置換しませんので注意。
	2. [SMTP-API](https://sendgrid.com/docs/API_Reference/SMTP_API/substitution_tags.html)に書いていることなので、`Web API v3`も適応されるのかよくわからないけど、まぁ多分、アルファベットのみで書くのがいい感じはする。

## テスト

書いたコードが正しく動くか確認したい時は、`SandBox`モードを使えば、相手先に送信せずに、リクエストの正当性をチェックをしてくれます。

# 大雑把なコード

```composer.json
{
    "name": "test/sendgrid_test_php",
    "require": {
        "sendgrid/sendgrid": "^5.0",
        "vlucas/phpdotenv": "^2.4"
    }
}
```

```.env
API_KEY=...
```

```php
<?php

require __DIR__ . '/vendor/autoload.php';

use SendGrid\Email;
use SendGrid\Mail;
use SendGrid\Content;
use SendGrid\Personalization;
use SendGrid\MailSettings;
use SendGrid\SandBoxMode;

function helloEmail()
{
    $from = new Email("Example Hosting Service", "info@example.com");
    $mail = new Mail();
    $mail->setFrom($from);

    // メッセージ作成. textメールとhtmlメールを送信をする
    $content = new Content("text/plain",
    	"some text here\n%name%様 御中\n\nこれは%name%様宛に送信しています。");
    $mail->addContent($content);
    $content = new Content("text/html",
    	"<html><body>some text here<br/>%name%御中<br /><br />これは%name%様宛に送信しています。</body></html>");
    $mail->addContent($content);

	// 宛先一覧
    $name_list = [
        [ "人名漢字", "A1@example.com" ],
        [ "Aさん", "B1@example.com" ],
        [ "Bさん", "C1@example.com" ],
    ];

    foreach($name_list as $names){
        $personalization = new Personalization();
        $email = new Email($names[0], $names[1]);
        $personalization->addTo($email);
        $personalization->setSubject("Hello World from the SendGrid PHP Library %name% 様宛");
        
        // ここで追加したHeaderは、ユーザ側まで行く
        $personalization->addHeader("X-Test", "test");
        $personalization->addHeader("X-Mock", "true");
        
        // 本文とSubjectの「%name%」をSendGrid側で置換させる
        $personalization->addSubstitution("%name%", $names[0]);
        $mail->addPersonalization($personalization);
    }

	// カテゴリー名はアルファベットのみ
    $mail->addCategory("test_sending");

    echo json_encode($mail, JSON_PRETTY_PRINT), "\n";
    return $mail;
}

$dotenv = new Dotenv\Dotenv(__DIR__);
$dotenv->load();

$apiKey = getenv('API_KEY');
$sg = new \SendGrid($apiKey);
$mail = helloEmail();

$mail_settings = new MailSettings();

// サンドボックスモードにする事で、送信しないが、リクエストの正当性を確認する
$sandbox_mode = new SandBoxMode();
$sandbox_mode->setEnable(true);
$mail_settings->setSandboxMode($sandbox_mode);
$mail->setMailSettings($mail_settings);

$response = $sg->client->mail()->send()->post($mail);
echo $response->statusCode();
echo $response->body();
echo $response->headers();

```