Menu

BLOG ベアメールブログ

ベアメールの配信ログAPIを利用して、リストクリーニングを自動化する方法

メール配信を行う際、送信結果のログを管理することは非常に重要です。特に大量のメールを送信する環境では、どのメールが正常に送信され、どのメールがエラーとなったのかを把握し、配信リストを最適化することで、配信成功率の向上につながります。
当社が提供するベアメール メールリレーサービスでは、メールの配信ログを取得するAPI(以下、ログAPI)を提供しています。本記事ではこのログAPIを活用し、配信ログの取得・解析、リストクリーニングを自動化する方法について解説をします。

配信ログAPIとは

配信ログAPIは、送信したメールのログを取得するためのAPIです。

配信ログにはステータスコードや送信日付、メッセージIDなどの情報が含まれています。配信ログを確認することで、エラーの有無、そのエラーの種類を把握することができます。

そもそもAPIとは?

APIとは、Application Programming Interfaceの略で、異なるソフトウェアやシステムが相互にやり取りを行うためのインターフェースです。APIを利用することで、開発者は特定の機能をプログラムから簡単に呼び出して、データを取得したり、送信したりすることができます。

APIには様々な種類がありますが、ベアメールではWeb APIと呼ばれる、httpsプロトコルを使用するAPIを提供しています。

配信ログAPIの主な機能

配信ログAPIは、先述の通り送信したメールの配信ステータス等の情報をAPI経由で取得できます。

ベアメール メールリレーサービスでは、管理画面で配信ログをCSVでダウンロードすることができますが、APIを使うことで配信ログの取得を自動化できます。

このログAPIを活用することで、例えばハードバウンスの場合は配信リストから削除する、などの対応を効率化できます。

配信ログAPIの仕様

まずは配信ログAPIの仕様について説明したいと思います。

配信ログAPIはWeb APIだと前述しましたが、Web APIは [ベースとなるURL+リクエストに必要な値] の形で実行する必要があります。ベースとなるURLをエンドポイント、リクエストに必要な値をリクエストパラメータといいます。

レスポンスはJSON形式となっており、データ構造が視覚的に理解しやすく、プログラム的にも処理がしやすくなっています。

APIエンドポイントとリクエストパラメータ

配信ログAPIのエンドポイントは以下のようになっています。

  • エンドポイント:https://bmapi.baremetal.jp/api/v1/external/baremail/getUserLog/
  • データ形式:JSON
  • メソッド:POST

リクエストパラメータは下記の内容が必須項目となります。

項目内容
loginid管理画面ログイン時のIDアカウント作成時のメールアドレス
passwd管理画面ログイン時のパスワードアカウント作成時のパスワード
uidユーザID(SLで始まる番号)SLから始まる番号
kind取得するログの種類a: ベアメールシステムが受け取ったメールのログ(アクセプトログ)
s: ベアメールシステムから送信されたメールのログ(センドログ)
term取得したいデータの期間日付のみの指定と日時での指定の2通りが可能
※直近31日間のみ指定可能
<日付のみ指定の例>
{“start”:”2017-06-01”,”end”:”2017-06-10”}
<日時指定の例>
{“start”:”2017-06-01 10:00:00”,”end”:”2017-06-10 19:59:59”}

レスポンスには下記の情報が含まれます。

項目内容
codeステータスコード
200: 正常
200以外: エラー
message処理メッセージ。主にエラー時にエラー内容が記述される
versionAPIのバージョン
totalログの合計件数
log_objectログ情報
ログ1件毎に配列に格納
<例>
log_object[0].. 1件目のログ
log_object[1].. 2件目のログ

レスポンスのlog_objectにはログの詳細情報が含まれますが、リクエストのkindパラメータで指定した、取得するログの種類によって取れる情報が異なります。

kind に a を指定した場合(ベアメールシステムが受け取ったメールのログ)

項目内容
日付yyyy-mm-dd
時間hh:mm:ss
送信元IPアドレス送信元のIPアドレス
Toメールアドレス宛先メールアドレス
FromメールアドレスエンベロープFromのアドレス
ステータスOK または NG
メッセージID例:<20230828122600.642952A0BA5@link.co.jp>
※ 320byteを超えた場合は超過分が切り捨てられます

※専用環境をご利用中のお客さまは、配信システムのバージョンによりメッセージIDが出力されないものがありますのでご注意下さい。

kind に s を指定した場合(ベアメールシステムから送信されたメールのログ)

項目内容
日付yyyy-mm-dd
時間hh:mm:ss
送信元IPアドレス送信元のIPアドレス
ステータスOK, NG または RETRY
ステータスコード例:250, 550
Toメールアドレス宛先メールアドレス
FromメールアドレスエンベロープFromのアドレス
メッセージ例:250_2.0.0_Ok:_queued_as_96CEF23C01D5
メッセージID例:<20230828122600.642952A0BA5@link.co.jp>
※ 320byteを超えた場合は超過分が切り捨てられます

※専用環境をご利用中のお客さまは、配信システムのバージョンによりメッセージIDが出力されないものがありますのでご注意下さい。

配信ログAPIの実行方法

このことを踏まえ、Linuxのcurlコマンドで実行してみましょう。

curlはコマンドラインからHTTPリクエストを送信するためのツールです。
コマンドとしては下記のような形になります。

出力はJSON形式となるため、最後にjqを付けています。
また、POSTとなるためヘッダーを指定する必要があります。

curl -X POST "https://bmapi.baremetal.jp/api/v1/external/baremail/getUserLog/" -H "Content-Type: application/json" -d '{"loginid": "xxxxxxx@link.cojp", "passwd": "xxxxxxxxx", "uid": "SL00xxxxxxx", "kind": "s", "term": {"start": "2025-02-28", "end": "2025-02-28"}}' | jq

実行すると下記のような出力結果を得られます。

{
  "code": 200,
  "message": "OK",
  "version": true,
  "total": 1,
  "log_object": [
    "2025-02-28,00:04:20,192.0.2.123,OK,250,xxxxxx@link.co.jp,yyyyyyyy@baremail.jp,250_2.0.0_Ok:_queued_as_B52s6r6t9h1,"
  ]
}

ちゃんと結果が取得できましたが、curlコマンドから実行するとコマンドが非常に長くなってしまいます。これでは、変更した時の入力間違えや、再利用がしにくいなどの問題があります。
また、パスワードを直接入力することになるため、それがコマンド履歴に残ってしまいセキュリティ的にも良くありません。

ベアメール メールリレーサービスではPHPで作られたサンプルコードを提供しています。
前述のcurlのサンプルコードではコード中にIDやPWを直接入力していますが、こちらでは別途設定用のファイルを用意することで、セキュリティを高めることができます。

※baremail_api_sample.php

 "2025-02-28",
		"end" => "2025-02-28"
		); 
	$postarr = array(
		"loginid" => "xxxxx@sample.jp",
		"passwd" => "xxxxxx",
		"uid" => "SLxxxxxx",
		"kind" => "s",
		"term" => $term
		); 
	$postdata = json_encode($postarr); 

	$ch = curl_init($url); 
	curl_setopt($ch, CURLOPT_POST, true); 
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); 
	curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json")); 
	$result = curl_exec($ch); 
	curl_close($ch); 
	$retarr = json_decode($result,true); 
	print_r($retarr); 
?>

では実行してみましょう。

# php baremail_api_sample.php

先ほどcurlコマンドで実行した時と同じ結果を得られました。

{
  "code": 200,
  "message": "OK",
  "version": true,
  "total": 1,
  "log_object": [
    "2025-02-28,00:04:20,192.0.2.123,OK,250,xxxxxx@link.co.jp,yyyyyyyy@baremail.jp,250_2.0.0_Ok:_queued_as_B52s6r6t9h1,"
  ]
}

このような配信ログをもとに、送信に失敗したメールを特定し、エラー解析を進めることができます。

エラーメールの抽出方法

取得したログデータから、配信が失敗しているメールのみを抽出するには、”log_object”内のステータス フィールド(3番目)がNG となっているデータを取得する必要があります。また、ステータスコード フィールド(4番目)もリストクリーニングに重要な要素です。

ステータスコードの意味については、ベアメールブログに詳しく記載されておりますので、宜しければご確認下さい。
メールのエラーコード(SMTPステータスコード)の意味と対策 | ベアメールブログ

今回はステータスフィールドが「NG」、ステータスコードフィールドが「550」になっているものを抽出したいと思います。
550エラーはRFCに定義されている一般的なエラーコードで、宛先が存在しない等の理由で発生するハードバウンスと呼ばれるエラーです。

ハードバウンスについては以下の記事で詳しく解説しています。
バウンスメールのリスクを解説!具体的な対策も紹介 | ベアメールブログ

宛先が存在しないメールアドレスにずっと送信し続けてしてしまうと、メールキャリアからスパムメールの送信者と判断され、送信元IPやドメインのレピュテーション(信頼度)が下がる可能性があります。レピュテーションが低下するとメールキャリアから受信拒否されてしまい、どんどんメールが届きにくくなる負のスパイラルが発生するリスクがありますので、早めの対処が肝要です。

550エラーとなったログを抽出するPHPのコードは下記のようになります。

$retarr = array_filter($data["log_object"], function ($log) {
    $fields = explode(",", $log);
    return isset($fields[3], $fields[4]) && $fields[3] === "NG" && $fields[4] === "550";
});

実行すると、

( [0] => 2025-02-28,00:04:20,192.168.xx.xxx,NG,550,xxxxxx@link.co.jp,yyyyyyyy@baremail.jp,550_5.1.1_User_unknown,<zzzzzz.yyyyyyyyyyyy%yyyyyyyy@baremail.jp> )

このように550エラーとなったログだけを抽出することができます。

リストクリーニングの自動化

エラーメールを抽出した後、それらのアドレスを自動的にリストから除外することで、不要な宛先への送信を防ぐことができます。

リスト自体はCSVやDB、SaaSなどで管理している方が多いかと思いますが、今回は550エラーとなったメールアドレスを、MySQLで管理している配信リストから自動的にクリーニングしたいと思います。

環境は下記の通りです。

OS環境

# cat /etc/redhat-release
AlmaLinux release 8.10 (Cerulean Leopard)

PHP

# php -v
PHP 7.2.24 (cli) (built: Oct 22 2019 08:28:36) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

Mysql

# mysql --version
mysql  Ver 8.4.4 for Linux on x86_64 (MySQL Community Server - GPL)

mysqlの中に「mail_list」テーブルを作成しましたので、この中のリストからクリーニングしていきます。

テーブル

mysql> show tables;
+---------------------+
| Tables_in_mail_list |
+---------------------+
| mail_list           |
+---------------------+

簡易的ですが、カラムは下記のような内容にしました。

カラム

mysql> select * from mail_list ;
+----+-----------+-------------------+
| id | user_name | user_mailadd      |
+----+-----------+-------------------+
|  1 | aaaa      | aaaa@example.com  |
|  2 | bbbb      | bbbb@baremail.jp  |
|  3 | cccc      | cccc@example.org  |
|  4 | dddd      | dddd@link.co.jp   |
|  5 | eeee      | eeee@example.net  |
+----+-----------+-------------------+

では、PHPのコードを書いていきます。

 "2025-02-28",
        "end" => "2025-02-28"
        );
        
    $postarr = array(
        "loginid" => "xxxxx@sample.jp",
        "passwd" => "xxxxxx",
        "uid" => "SLxxxxxx",
        "kind" => "s",
        "term" => $term
        ); 
    
    $postdata = json_encode($postarr);
    
    // APIリクエストを実行
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
    $result = curl_exec($ch);
    curl_close($ch);
    
    $retarr = json_decode($result, true);
    print_r($retarr);
    
    // MySQL接続設定(PDOを使用)
    $host = "localhost"; 	// ホスト名
    $user = "DB_USER"; 		// DBユーザー名
    $pass = "DB_PASSWORD"; 	// DBパスワード
    $dbname = "mail_list"; 	// データベース名
    
    try {
        $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
        if (isset($retarr["log_object"]) && is_array($retarr["log_object"])) {
            foreach ($retarr["log_object"] as $log) {
                $fields = explode(",", $log);
                if (count($fields) >= 6 && $fields[3] === "NG" && $fields[4] === "550") {
		     // 5フィールド目のToアドレスを取得
                    $email = $fields[5];    
                    // メールアドレスをDBから削除
                    $stmt = $pdo->prepare("DELETE FROM mail_list WHERE user_mailadd = ?");
                    if ($stmt->execute([$email])) {
                        echo "削除成功: $email\n";
                    } else {
                        echo "削除失敗: $email\n";
                    }
                }
            }
        }
    } catch (PDOException $e) {
        die("データベースエラー: " . $e->getMessage());
    }
?>

実行すると、対象のログが合った場合は下記のように出力されます。

削除成功: eeee@example.net

ちゃんと削除されたか、DBを確認してみましょう。

mysql> select * from mail_list ;
+----+-----------+-------------------+
| id | user_name | user_mailadd      |
+----+-----------+-------------------+
|  1 | aaaa      | aaaa@example.com  |
|  2 | bbbb      | bbbb@baremail.jp  |
|  3 | cccc      | cccc@example.org  |
|  4 | dddd      | dddd@link.co.jp   |
+----+-----------+-------------------+

テーブルから5番目のカラムが削除されていることが確認できました。

今回はDB上から直接削除しましたが、実際には配信フラグの操作や、別のAPIを使いリストから削除するなどの運用になるかと思いますので、ご使用の環境に合わせて頂ければと思います。

※今回作成したプログラムは最小限の機能しか持たせていないので、実際に運用で使用される際にはご注意下さい。

まとめ

本記事では配信ログAPIを活用して、エラーログを取得、リストクリーニングを自動化する方法を紹介しました。不要な宛先への送信を防ぎ、配信成功率を向上させることはメールを送信する上でとても大事なことです。
適切なリストクリーニングを行うことで、

  • メールサーバーの評価を維持
  • 送信コストの削減
  • ドメインレピュテーションを守る
  • エンドユーザーに適切なメールを届ける

ことが可能になります。
本記事が、皆さまのメール運用の改善に役立つことを願っています。