PHP で Google reCAPTCHA v3 付きのお問い合わせフォームを作る (2)

[PHP で Google reCAPTCHA v3 付きのお問い合わせフォームを作る (1)](https://qiita.com/syuus/items/751aa46e5fd5bf0ae6d5) の続きです。
前回までで、 Google reCAPTCHA v3 スコア算出とそれによる条件分岐を作成しました。
ここからは Swift Mailer でのメール送信処理を書いていきます。

メール送信処理
===

日本語メールを扱うための設定
---

Swift Mailer の公式ドキュメントにもある、日本語メールを扱うための設定を追加します。
[Using Swift Mailer for Japanese Emails](https://swiftmailer.symfony.com/docs/japanese.html)

```php:send.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use ReCaptcha\ReCaptcha as ReCaptcha;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  $response = (new ReCaptcha('<シークレット キー>'))
                  ->setExpectedHostname($_SERVER['SERVER_NAME'])
                  ->setExpectedAction('inquiry')
                  ->setScoreThreshold(0.5)
                  ->verify($_POST['token'], $_SERVER['REMOTE_ADDR']);
  $challenge_result = $response->toArray();

  if ($challenge_result['success']) {
    \Swift::init(function () {
    \Swift_DependencyContainer::getInstance()
      ->register('mime.qpheaderencoder')
      ->asAliasOf('mime.base64headerencoder');

      \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
    });
  }
}
```

SMTP 認証情報を設定する
---

以下のコードは Gmail の SMTP サーバを使用した例ですが、お使いになるものに置き換えてください。

```php:send.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use ReCaptcha\ReCaptcha as ReCaptcha;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  $response = (new ReCaptcha('<シークレット キー>'))
                  ->setExpectedHostname($_SERVER['SERVER_NAME'])
                  ->setExpectedAction('inquiry')
                  ->setScoreThreshold(0.5)
                  ->verify($_POST['token'], $_SERVER['REMOTE_ADDR']);
  $challenge_result = $response->toArray();

  if ($challenge_result['success']) {
    \Swift::init(function () {
    \Swift_DependencyContainer::getInstance()
      ->register('mime.qpheaderencoder')
      ->asAliasOf('mime.base64headerencoder');

      \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
    });

    $transport = (new \Swift_SmtpTransport('smtp.gmail.com', 587, 'tls'))
        ->setUsername('username@gmail.com')
        ->setPassword('****************');
  }
}
```

送信先・件名・本文を設定する
---

バリデーション処理などは一旦おいておいて、とりあえず送信テストをするための記述を行います。
`setTo()` メソッドは例外が起きる可能性があるので、 try-catch で例外処理をしておきます。

[Sending Emails in Batch](https://swiftmailer.symfony.com/docs/sending.html#sending-emails-in-batch)

> If you add recipients automatically based on a data source that may contain invalid email addresses, you can prevent possible exceptions by validating the addresses using Egulias\EmailValidator\EmailValidator (a dependency that is installed with Swift Mailer) and only adding addresses that validate. Another way would be to wrap your setTo(), setCc() and setBcc() calls in a try-catch block and handle the Swift_RfcComplianceException in the catch block.

`info@example.com` の部分は送信したいメールアドレスに置き換えてください。

```php:send.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use ReCaptcha\ReCaptcha as ReCaptcha;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  $response = (new ReCaptcha('<シークレット キー>'))
                  ->setExpectedHostname($_SERVER['SERVER_NAME'])
                  ->setExpectedAction('inquiry')
                  ->setScoreThreshold(0.5)
                  ->verify($_POST['token'], $_SERVER['REMOTE_ADDR']);
  $challenge_result = $response->toArray();

  if ($challenge_result['success']) {
    \Swift::init(function () {
    \Swift_DependencyContainer::getInstance()
      ->register('mime.qpheaderencoder')
      ->asAliasOf('mime.base64headerencoder');

      \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
    });

    $transport = (new \Swift_SmtpTransport('smtp.gmail.com', 587, 'tls'))
        ->setUsername('username@gmail.com')
        ->setPassword('****************');

    $mailer = new \Swift_Mailer($transport);

    $message = (new \Swift_Message('お問い合わせフォームからお問い合わせがありました'))
        ->setFrom([filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL) => filter_input(INPUT_POST, 'name', FILTER_SANITIZE_FULL_SPECIAL_CHARS)])
        ->setBody(
          'お名前: ' . filter_input(INPUT_POST, 'name', FILTER_SANITIZE_FULL_SPECIAL_CHARS) . PHP_EOL .
          'メールアドレス: ' . filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL) . PHP_EOL .
          'お問い合わせ内容: ' . filter_input(INPUT_POST, 'contents', FILTER_SANITIZE_FULL_SPECIAL_CHARS));

    try {
      $message->setTo(['info@example.com']);
    } catch (\Swift_RfcComplianceException $e) {
      echo '不正なメールアドレスです。';
    }
  }
}
```

送信処理
---

```php:send.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use ReCaptcha\ReCaptcha as ReCaptcha;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  $response = (new ReCaptcha('<シークレット キー>'))
                  ->setExpectedHostname($_SERVER['SERVER_NAME'])
                  ->setExpectedAction('inquiry')
                  ->setScoreThreshold(0.5)
                  ->verify($_POST['token'], $_SERVER['REMOTE_ADDR']);
  $challenge_result = $response->toArray();

  if ($challenge_result['success']) {
    \Swift::init(function () {
    \Swift_DependencyContainer::getInstance()
      ->register('mime.qpheaderencoder')
      ->asAliasOf('mime.base64headerencoder');

      \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
    });

    $transport = (new \Swift_SmtpTransport('smtp.gmail.com', 587, 'tls'))
        ->setUsername('username@gmail.com')
        ->setPassword('****************');

    $mailer = new \Swift_Mailer($transport);

    $message = (new \Swift_Message('お問い合わせフォームからお問い合わせがありました'))
        ->setFrom([filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL) => filter_input(INPUT_POST, 'name', FILTER_SANITIZE_FULL_SPECIAL_CHARS)])
        ->setBody(
          'お名前: ' . filter_input(INPUT_POST, 'name', FILTER_SANITIZE_FULL_SPECIAL_CHARS) . PHP_EOL .
          'メールアドレス: ' . filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL) . PHP_EOL .
          'お問い合わせ内容: ' . filter_input(INPUT_POST, 'contents', FILTER_SANITIZE_FULL_SPECIAL_CHARS));

    try {
      $message->setTo(['info@example.com']);
    } catch (\Swift_RfcComplianceException $e) {
      echo '不正なメールアドレスです。';
    }

    try {
      $send_result = $mailer->send($message);
    } catch (\Swift_TransportException $e) {
      echo 'メール送信エラーです。';
    }

    if ($send_result) {
      echo 'メールを送信しました。';
    } else {
      echo 'メール送信に失敗しました。';
    }
  }
}
```

とりあえずここまででメールの送信テストが可能な状態になりました。
すべての入力欄を埋めて **送信する** ボタンを押して試してみてください。

このままでは実用に耐えないので、

- バリデーション処理
- エラーが発生したときにお問い合わせフォームに戻し、エラーの内容を表示する
- メール本文をテンプレート化して編集しやすくする

など、細かな改善を次回以降で行っていきます。