PHPMailerでメールをSTMP送信する

#概要
[PHPMailer](https://github.com/PHPMailer/PHPMailer)を使ってSMTPでメールを送信するまでのメモです。
環境の都合でComposerを使用せず、ソースをDLして実装します。

PHPMailerは記事更新時点での最新バージョンを使用しています。

#PHPMailerの準備
[公式のGithubリポジトリ](https://github.com/PHPMailer/PHPMailer)からソースを入手します。
**「Clone or download」**からzipをDLすることが出来ます。
![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655954/8e657506-7dcc-923a-61b9-720e0e5a70ab.png)


zipを解凍すると「PHPMailer-master」というディレクトリができます。
使い勝手を考慮して「PHPMailer」にリネームし、ディレクトリごと好きな場所に置きます。

#PHPMailerを実装
まずは必要なファイルを読み込みます。
Composerを利用していないので、`require`で各ファイルを読み込む必要があります。


```send_mail.php
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;

// 設置した場所のパスを指定する
require('path/to/PHPMailer/src/PHPMailer.php');
require('path/to/PHPMailer/src/Exception.php');
require('path/to/PHPMailer/src/SMTP.php');

// Composerを利用した場合、requireは下記だけでOK
// require('path/to/vendor/autoload.php');
:
:
// 続きの処理
```

　
次にメール送信部分を実装します。
詳細なオプションの内容は[Githubのサンプル](https://github.com/PHPMailer/PHPMailer#a-simple-example)にも記載されています。

```send_mail.php
// 文字エンコードを指定
mb_language('uni');
mb_internal_encoding('UTF-8');
 
// インスタンスを生成（true指定で例外を有効化）
$mail = new PHPMailer(true);
 
// 文字エンコードを指定
$mail->CharSet = 'utf-8';
 
try {
  // デバッグ設定
  // $mail->SMTPDebug = 2; // デバッグ出力を有効化（レベルを指定）
  // $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str<br>";};

  // SMTPサーバの設定
  $mail->isSMTP();                          // SMTPの使用宣言
  $mail->Host       = 'mail.example.com';   // SMTPサーバーを指定
  $mail->SMTPAuth   = true;                 // SMTP authenticationを有効化
  $mail->Username   = 'user@example.com';   // SMTPサーバーのユーザ名
  $mail->Password   = 'password';           // SMTPサーバーのパスワード
  $mail->SMTPSecure = 'tls';  // 暗号化を有効（tls or ssl）無効の場合はfalse
  $mail->Port       = 465; // TCPポートを指定（tlsの場合は465や587）
 
  // 送受信先設定（第二引数は省略可）
  $mail->setFrom('from@example.com', '差出人名'); // 送信者
  $mail->addAddress('to@xxxx.com', '受信者名');   // 宛先
  $mail->addReplyTo('replay@example.com', 'お問い合わせ'); // 返信先
  $mail->addCC('cc@example.com', '受信者名'); // CC宛先
  $mail->Sender = 'return@example.com'; // Return-path
  
  // 送信内容設定
  $mail->Subject = '件名'; 
  $mail->Body    = 'メッセージ本文';  

  // 送信
  $mail->send();
} catch (Exception $e) {
  // エラーの場合
  echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
```

##実装のポイント
###・宛先の複数指定
宛先やCCは複数指定が可能です。

```php5
$mail->addAddress('one@xxxx.com');
$mail->addAddress('two@xxxx.com');
```

###・日本語の文字化け
日本語が文字化けする場合は`mb_encode_mimeheader()`でエンコードします。

```php5
$mail->setFrom('from@example.com', mb_encode_mimeheader('差出人名')); 
```

###・PHPMailerの定数
PHPMailerには[事前に定義されている定数](https://github.com/PHPMailer/PHPMailer/blob/b52fd6e8ad14908bc5a6c9ca7487bd0737fd0919/src/PHPMailer.php#L31)があります。
定数を使って値を指定しても、自分で記述してもOKです。

```php5
// どの書き方でもOK
$mail->SMTPSecure = 'tls';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // tls
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;    // ssl

$mail->Charset = 'utf-8'
$mail->CharSet = PHPMailer::CHARSET_UTF8; // utf-8
```

###・暗号化（TLS/SSL）を使用しない場合
本来は使用した方が良いですが、サーバーによっては使えないときがあります。
暗号化を使用しない場合は明示的にパラメータを指定します。

```php
// 下記をfalseにする
$mail->SMTPSecure  = false;
$mail->SMTPAutoTLS = false;
```
参考：[PHPMailer：SMTPエラー：SMTPホストに接続できませんでした](https://www.it-swarm.dev/ja/php/phpmailer%EF%BC%9Asmtp%E3%82%A8%E3%83%A9%E3%83%BC%EF%BC%9Asmtp%E3%83%9B%E3%82%B9%E3%83%88%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93%E3%81%A7%E3%81%97%E3%81%9F/969114534/)

###・デバッグログの出力
デバッグの出力は下記の2行で可能です。

```php
// デバッグ設定
$mail->SMTPDebug = 3;
$mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str<br>";};
```

●`SMTPDebug`でデバッグモードのレベルを指定します。
詳細は[公式のGithub](https://github.com/PHPMailer/PHPMailer/wiki/SMTP-Debugging)に説明があります。

●`Debugoutput`でデバッグの内容をechoすることができます。
メールサーバーへの接続からメール送信までのログが出力されるので、例外でキャッチできる内容より詳細な原因を調べることができます。

デバッグはechoだけでなく、syslogなどに出力することも可能なようです。
参考：[PHPMailerのログをSYSLOGに出力](https://www.spankyjpn.com/phpmailer-logto-syslog/)
　
**▼デバッグ出力結果**
![qiita_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655954/ae3b0c08-2d53-4f5a-2947-d6884d308392.png)

###・E_WARNINGが発生する
以下のエラーが発生する場合は、メールサーバーに接続出来ていない可能性があります。
（例外を有効にしていてもここで止まる場合があります。）

ホスト名・ポート番号・ユーザー名・パスワード等が正しいか確認しましょう。

```
E_WARNING stream_set_timeout() expects parameter 1 to be resource, 
bool given /path/to/PHPMailer/src/SMTP.php 344
```

###・sslのエラーが出る
PHPのバージョンによってはsslでローカルの証明書を確認する？仕様になっているそうです。
その場合は下記の設定を追記が必要です。

```php
$mail->SMTPOptions = array(
	'ssl' => array(
	'verify_peer' => false,
	'verify_peer_name' => false,
	'allow_self_signed' => true
));
```

参考：[PHP5.6でSMTPのhostがsslの場合に注意！](https://qiita.com/satthi/items/1eaf1f5c2e1170f398da)
[](https://stackoverflow.com/questions/26827192/phpmailer-ssl3-get-server-certificatecertificate-verify-failed)

#メールサーバーへの接続確認
Windowsのコマンドプロンプトから確認する方法です。
`telnet`コマンドを使います。

`telnet`が使えない場合は、
**【コントロールパネル＞プログラム＞Windowsの機能の有効化または無効化】** から
Telnet Clientの項目にチェックを入れて有効化してください。

```bash
telnet メールサーバーホスト ポート番号
```
上記のコマンドを実行して、接続できなければホスト名やポートを確認してください。

#おまけ：開発環境からのメール送信テスト
ローカルなどの開発環境からではメールサーバーに接続できなかったりします。
その際に簡単に送受信を行える「mailtrap」というサービスがあります。

:envelope: [mailtrap.io](https://mailtrap.io/)

![image02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655954/d744fed0-0182-5f7b-4ae5-fa38c320c63b.png)


無料の会員登録をするとSMPT/POP3のサーバー情報が与えられます。
こちらを指定してメールを送信すると、すべてmailtrapのDemoboxに届きます。

テストメールは宛先のメールボックスではなくmailtrapに届くので、テストメールで自分の受信箱がいっぱいになることもないので便利です。

#参考URL
- [PHPMailer の使い方](https://www.webdesignleaves.com/pr/php/php_phpmailer.php)
- [メール設定で最初につまずく『SMTP』『POP』『IMAP』 その意味＆設定方法は？](https://time-space.kddi.com/ict-keywords/kaisetsu/20170824/2081)
- [mailtrapを利用してメール送信のテスト](https://qiita.com/denshin_ROKU/items/a9d79494dfff67b64259)

#さいごに
実装については以上です。
PHPMailerは参考文献も多く、簡単にSMTPで送信できる便利なライブラリですね。