blastengineを使ってPHPで添付ファイル付きメールを送信する


[blastengine](https://blastengine.jp/)はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。

今回はblastengineを使ってPHPで添付ファイル付きメールを送信を行うまでの流れを解説します。

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/b07d7d9d-6150-d5f9-1bb7-b13846c8ddfc.jpeg)


## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## API経由で配信する

まずはAPIを使ってHTMLメールを配信する流れを紹介します。

### APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/6ce98f9e-6da2-b7fa-bcde-d358b6aec6ac.jpeg)


そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/4adebc33-f957-009d-2bd3-fda151bb63d1.png)

### 利用するライブラリについて

今回はPHPでHTTP通信を行うライブラリ[Guzzle, PHP HTTP client — Guzzle Documentation](https://docs.guzzlephp.org/en/latest/index.html)を利用します。インストールはcomposerを使っています。

```
composer require guzzlehttp/guzzle:^7.0
```

### ライブラリの読み込み

最初にGuzzleを読み込みます。

```php
// ライブラリの読み込み
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;
```

### 必要な変数を取得

今回はターミナル（コマンドプロンプト）から実行します。その際にユーザIDとAPIキーを渡す仕組みにしますので、スクリプト側で入力値を受け取ります。また、両方とも必須なので、入力がなかったらエラーとします。

```php
$user_id = getenv("BE_USERID");
$api_key = getenv("BE_APIKEY");
if ($user_id === false) {
	echo "ユーザIDは必須です";
	exit;
}
if ($api_key === false) {
	echo "APIキーは必須です";
	exit;
}
```

### トークンを生成する

APIリクエストするためのトークンを生成します。手順としては次のとおりです。

1. ユーザIDとAPIキーを連結する
2. SHA256のハッシュを生成する
3. ハッシュを全て小文字にする
4. 3の文字列をBASE64エンコードする

実際のコードで言うと、次のようになります。 `$token` がトークンです。

```php
// トークン生成
$str = "$user_id$api_key";
$token = base64_encode(strtolower(hash('sha256', $str)));
```

### APIリクエストする

では実際にメールを送信します。APIのエンドポイントは `https://app.engn.jp/api/v1/deliveries/transaction` になります。生成したトークンは `Authorization` ヘッダーに適用します。fromのemailやtoなど、メールアドレスは利用されるものに書き換えてください。

```php
// APIエンドポイント
$url = 'https://app.engn.jp/api/v1/deliveries/transaction';
// POSTデータ
$data = [
	"from" => [
			"email" => "sample@example.jp",
			"name" => "送信者サンプル"
	],
	"to" => "to@example.com",
	"subject" => "テスト件名",
	"encode" => "ISO-2022-JP",
	"text_part" => "テスト配信",
	"html_part" => "<!DOCTYPE html><html><header></header><body>sample html</body></html>"
];
$data = json_encode($data);

// ヘッダー
$headers = [
  "Authorization" => "Bearer $token"
];
```

リクエスト内容を組み立てます。注意点としては次の2点です。

1. メール内容（件名や宛先）はdataパラメータで送ります。Content-Typeはapplication/jsonです。
2. 添付ファイルはfileパラメータで送ります。複数指定可能です。

```php
// データ
$param = [
	// メール送信情報はdataキーで送信
	[
		'name' => 'data',
		'contents' => json_encode($data),
		'headers'  => ['Content-Type' => 'application/json']
	],
	// 添付ファイルの情報
	[
		'name' => 'file',
		'contents' => Psr7\Utils::tryFopen('./photo.jpg', "r"),		
		'headers'  => ['Content-Type' => mime_content_type('./photo.jpg')]
	],
	[
		'name' => 'file',
		'contents' => Psr7\Utils::tryFopen('./text.md', "r"),
		'headers'  => ['Content-Type' => mime_content_type('./text.md')]
	],
];

// リクエスト情報
$options = [
	'headers'     => $headers,
	'multipart'   => $param
];
```

後はGuzzleを使って送信します。

```php
// Guzzleで送信
$client = new Client();
$res = $client->request('POST', $url, $options);
```

### 結果

レスポンスを出力します。配信ID（delivery_id）は照会、変更および削除操作に必要です。

```php
echo $res;
// { delivery_id: 9 }
```

### 実行する

では実際にターミナル、またはコマンドプロンプトから実行してみます。 `YOUR_USER_ID` と `YOUR_API_KEY` はそれぞれ皆さんのものに置き換えてください。

```
$ BE_USERID=YOUR_USER_ID BE_APIKEY=YOUR_API_KEY php api.php
{ delivery_id: 9 }
```

### 全体のコード

今回のサンプルコードは次のようになります。実装時の参考にしてください。

```php
<?php
// ライブラリの読み込み
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;

// トークン生成に必要な情報を環境変数から読み込み
$user_id = getenv("BE_USERID");
$api_key = getenv("BE_APIKEY");
if ($user_id === false) {
    echo "ユーザIDは必須です";
    exit;
}
if ($api_key === false) {
    echo "APIキーは必須です";
    exit;
}
// トークン生成
$str = "$user_id$api_key";
$token = base64_encode(strtolower(hash('sha256', $str)));
// APIエンドポイント
$url = 'https://app.engn.jp/api/v1/deliveries/transaction';
// POSTデータ
$data = [
  "from" => [
		"email" => "sample@example.jp",
		"name" => "送信者サンプル"
  ],
	"to" => "to@example.com",
  "subject" => "テスト件名",
  "encode" => "ISO-2022-JP",
  "text_part" => "テスト配信",
  "html_part" => "<!DOCTYPE html><html><header></header><body>sample html</body></html>"
];

// ヘッダー
$headers = [
  "Authorization" => "Bearer $token"
];

// データ
$param = [
	// メール送信情報はdataキーで送信
	[
		'name' => 'data',
		'contents' => json_encode($data),
		'headers'  => ['Content-Type' => 'application/json']
	],
	// 添付ファイルの情報
	[
		'name' => 'file',
		'contents' => Psr7\Utils::tryFopen('./photo.jpg', "r"),		
		'headers'  => ['Content-Type' => mime_content_type('./photo.jpg')]
	],
	[
		'name' => 'file',
		'contents' => Psr7\Utils::tryFopen('./text.md', "r"),
		'headers'  => ['Content-Type' => mime_content_type('./text.md')]
	],
];

// リクエスト情報
$options = [
	'headers'     => $headers,
	'multipart'   => $param
];

// Guzzleで送信
$client = new Client();
$res = $client->request('POST', $url, $options);

// 結果の出力
echo $res->getBody();
```

## SMTPリレーでの配信

次にSMTPリレーを使った方式です。

### IPアドレスの登録

SMTPリレーを利用する場合、まず接続元サーバのIPアドレスを管理画面で登録する必要があります。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/6efd1d73-bc5a-41e9-57e3-a93767c0fe31.jpeg)


IPアドレスの設定ダイアログで、接続元サーバのIPアドレスを入力してください。

![getting-started-7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/a63b13b7-6ab1-3cb9-90fc-95254ee009f4.jpeg)

### Postfixの編集

ネットで検索してよく出てくるphp.iniのSMTPサーバ設定はWindows向きの設定になります。恐らくLinuxサーバを利用するケースの方が多いが、php.iniの編集ではないので注意してください。Linuxの場合はPostfixを利用して配信します。この場合、`/etc/postfix/main.cf` を編集します。

下記1行を追加して保存します。blastengineのSMTPサーバアドレスは `smtp.engn.jp` 固定になります。ポート番号は25/587/2525より選択してください。

```
relayhost = smtp.engn.jp:587
```

Postfixが起動していない場合は起動してください。起動している場合には再起動が必要です。

```
$ sudo postfix start
// または
$ sudo postfix restart
```

### メール配信する

添付ファイルを付ける場合にはPHPMailerを使うのが手軽です。まずcomposerを使ってライブラリをインストールします。

```
composer require phpmailer/phpmailer
```

まずライブラリを読み込みます。

```php
<?php
// ライブラリの読み込み
require 'vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
```

次にPHPMailerオブジェクトを作成します。

```php
// PHPMailerオブジェクトの作成
$mail = new PHPMailer();
//日本語用設定
$mail->CharSet = "utf-8";
```

配信元、先を設定します。

```php
// 送信元の設定
$mail->setFrom('from@example.jp', mb_encode_mimeheader("Blastengine 管理人", "UTF-8"));  
// 配信先の設定
$mail->addAddress('user@example.com', mb_encode_mimeheader("ユーザー名", "UTF-8")); 
```

件名、本文を設定します。

```php
//　コンテンツの設定
$mail->isHTML(true);                                                    // HTML形式を指定
$mail->Subject = mb_encode_mimeheader("添付ファイル付きメール", "UTF-8"); // 件名
$mail->Body  = mb_encode_mimeheader('メッセージ <b>BOLD</b>', "UTF-8");  // HTML本文
$mail->AltBody = mb_encode_mimeheader('テキストメッセージ', "UTF-8");     // テキスト本文
```

添付ファイルを追加します。

```php
// 添付ファイルを追加します
$mail->addAttachment('./photo.jpg'); 
$mail->addAttachment('./text.md'); 
```

最後に送信を実行します。

```php
$mail->send();  //送信
```

### 全体のコード

今回のサンプルコードは次のようになります。実装時の参考にしてください。

```php
<?php
// ライブラリの読み込み
require 'vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

// PHPMailerオブジェクトの作成
$mail = new PHPMailer();
//日本語用設定
$mail->CharSet = "utf-8";
 
// 送信元の設定
$mail->setFrom('from@example.jp', mb_encode_mimeheader("Blastengine 管理人", "UTF-8"));  
// 配信先の設定
$mail->addAddress('user@example.com', mb_encode_mimeheader("ユーザー名", "UTF-8")); 


//　コンテンツの設定
$mail->isHTML(true);                                                    // HTML形式を指定
$mail->Subject = mb_encode_mimeheader("添付ファイル付きメール", "UTF-8"); // 件名
$mail->Body  = mb_encode_mimeheader('メッセージ <b>BOLD</b>', "UTF-8");  // HTML本文
$mail->AltBody = mb_encode_mimeheader('テキストメッセージ', "UTF-8");     // テキスト本文

// 添付ファイルを追加します
$mail->addAttachment('./photo.jpg'); 
$mail->addAttachment('./text.md'); 

$mail->send();  //送信
```

## まとめ

クラウドサービスではSMTPポートが塞がれている場合があるので、そうした時にはAPI経由を利用してください。SMTPリレーを使えば、より信頼性高く、安定した配信が実現できるでしょう。

APIとSMTPリレー、それぞれの要件に合わせて最適な方を選択してください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)