【Laravel】SendGridのWeb APIを利用してメール送信を実装


# 実装手順
SendGridでの設定は省略します。

1. .envにトークンを設定
2. ライブラリをインストール
3. githubのサンプルコードで仮実装
4. 処理を分ける
5. テンプレートを用意する。

# .envにトークンを設定
```:.env
SENDGRID_API_KEY=<SndGridで取得したトークン>
```
# ライブラリをインストール
```sh
composer require sendgrid/sendgrid
```

# githubのサンプルコードで仮実装
とりあえず、サンプルコードを動かしてみます。
必要なものをuseして、適当なメソッドに貼り付けます。
ルーティングの設定を忘れずに。

```php:TestMailController.php

(省略)

use SendGrid;
use SendGrid\Mail\Mail;

(省略)

public function send(Mail $email)
{
    $email->setFrom("test@<登録したドメイン>", "Example User"); // 送信元
    $email->setSubject("Sending with Twilio SendGrid is Fun"); // タイトル
    $email->addTo("<受け取れるメールアドレス>", "Example User"); // 送信先
    $email->addContent("text/plain", "and easy to do anywhere, even with PHP"); // プレーンテキストメール
    $email->addContent(
        "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"  // HTMLメール
    );

    $sendgrid = new SendGrid(env('SENDGRID_API_KEY'));

    try {
        $response = $sendgrid->send($email);
        print $response->statusCode() . "\n";
        print_r($response->headers());
        print $response->body() . "\n";
    } catch (Exception $e) {
        echo 'Caught exception: '. $e->getMessage() ."\n";
    }
}
```

送信が完了したら、202から始まるテキストが表示されます。

# 処理を分ける
SendGrid以外のサービスを利用することになった場合でも、少ない修正で済むようにする!
ということまではしていません。あしからず。

まずは、`$sendgrid = new SendGrid(env('SENDGRID_API_KEY'));`の部分をDIできるように、バインディングします。
以下のように登録することで、引数にトークンが渡された状態でDIされます。

```php:AppServiceProvider.php

use SendGrid;

(省略)

public function register()
{
    $this->app->bind('SendGrid', function ($app) {
        return new SendGrid(env('SENDGRID_API_KEY'));
    });
}
```

というわけで、TestMailControllerを以下の通り修正

```php:TestMailController.php
public function send(Mail $email, SendGrid $sendgrid) // <-追記
{
    // $sendgrid = new SendGrid(env('SENDGRID_API_KEY')); <-この記述がいらなくなる。
}
```

次に、メール構築部分の処理を分離していきます。
app/Mail/TestMail.phpを作成し、そのコンストラクターでメールを構築するようにします。

```php:app/Mail/TestMail.php
<?php

namespace App\Mail;

use SendGrid\Mail\Mail;

class TestMail extends Mail // SendGrid\Mail\Mailを継承
{
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($args)
    {
        $this->setFrom("test@<登録したドメイン>", "Example User");
        $this->setSubject($args->message);
        $this->addTo($args->to, "Example User");
        $this->addContent("text/plain", "and easy to do anywhere, even with PHP");
        $this->addContent(
            "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
        );

        return $this;
    }
}
```

TestMailControllerを以下の通り修正

```php:TestMailController.php

(省略)

use SendGrid;
use SendGrid\Mail\Mail;
use App\Mail\TestMail; // 追記

(省略)

public function send(Mail $email, SendGrid $sendgrid)
{
    try {
        $response = $sendgrid->send(new TestMail($this->args));

        $message = 'メールを送信しました。'); // ついでに修正
    } catch (Exception $e) {
        report($e); // ついでに修正
        $message = 'メール送信に失敗しました。'); // ついでに修正
    }

    return redirect()->back()->with('flash_message', $message); // ついでに修正
}
```

# テンプレートを用意する。
次にBladeテンプレートを用意して、それを利用するようにします。
(以下は、プレーンテキスト用のテンプレートです。)

```html:views/emails/test_mail.blade.php
テストメールテンプレート
変数{{ $hoge }}{{ $fuga }}も渡せます。
```

テンプレートを利用するには、viewインスタンスを文字列にキャストしたものを、
addContentに渡せばOKです。

```php:app/Mail/TestMail.php
<?php

namespace App\Mail;

use SendGrid\Mail\Mail;

class TestMail extends Mail // SendGrid\Mail\Mailを継承
{
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($args)
    {
        $hoge = 'hoge';
        $fuga = 'fuga';

        $this->setFrom("test@<登録したドメイン>", "Example User");
        $this->setSubject($args->message);
        $this->addTo($args->to, "Example User");
        $this->addContent(
            "text/plain",
            strval(view('emails.test_mail', compact('hoge', 'fuga'))) // viewインスタンスを文字列にキャスト
        );

        // $this->addContent(
        //     "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
        // );

        return $this;
    }
}
```

複数のメールアドレスに対して送信する場合は、`addTos`メソッドを利用すればいいようです。
[Send an Email to Multiple Recipients](https://github.com/sendgrid/sendgrid-php/blob/master/USE_CASES.md#send-an-email-to-multiple-recipients)

```php
$tos = [ 
    "test+test1@example.com" => "Example User1",
    "test+test2@example.com" => "Example User2",
    "test+test3@example.com" => "Example User3"
];
$email->addTos($tos);
```

この場合、toに複数のアドレスを書き込んでいる状態なので、受信者は全てのメールアドレスを見れてしまいますので、気をつけてください。
マーケティングメールなどを送るときは、メールアドレス分ループさせるのが良さそうです。

以上です。

# 参考
https://github.com/sendgrid/sendgrid-php#usage