2026年6月16日
2026年6月16日
WordPressのメール送信を制限してスパム送信を防ぐ方法
はじめに
WordPressサイトが乗っ取られたり脆弱なプラグインを悪用されると、スパムメール送信の踏み台にされることがあります。IPがブラックリストに登録される前に、送信レート制限と監視を設定することが重要です。
症状・原因
- サーバーのメールキューが大量のメールで溢れている
- IPアドレスがスパムブラックリストに登録された
- ホスティング会社からメール送信制限の警告が届いた
- wp_mail() が予期せず大量呼び出しされている
解決手順
ステップ1:現在のメール送信状況を確認する
# Postfixのメールキューを確認
mailq | head -50
postqueue -p | grep -c "^[A-F0-9]" # キュー内のメール数
# 送信元プロセスを確認
grep "from=<" /var/log/mail.log | tail -100 | awk '{print $7}' | sort | uniq -c | sort -rn
# WordPress から送信されているか確認
grep "wp-mail\|wp_mail\|phpmailer" /var/log/mail.log | tail -50
# 過去1時間の送信数
grep "$(date +'%b %d %H')" /var/log/mail.log | grep "status=sent" | wc -l
ステップ2:wp_mail にレート制限を実装する
// functions.php: wp_mail 送信レート制限
add_filter('wp_mail', function(array $args): array {
$key = 'mail_count_' . date('YmdH');
$count = (int) get_transient($key);
$limit = 50; // 1時間あたりの上限
if ($count >= $limit) {
// 上限超過:ログに記録してメールをブロック
error_log(sprintf(
'[WP Mail Limit] Blocked: to=%s subject=%s count=%d',
is_array($args['to']) ? implode(',', $args['to']) : $args['to'],
$args['subject'],
$count
));
// 空の受信者を返してメール送信をキャンセル
$args['to'] = '';
return $args;
}
set_transient($key, $count + 1, HOUR_IN_SECONDS);
return $args;
});
// 送信失敗をログに記録
add_action('wp_mail_failed', function(WP_Error $error): void {
error_log('[WP Mail Failed] ' . $error->get_error_message());
});
ステップ3:メール送信ログを実装する
// functions.php: 全メール送信をカスタムテーブルに記録
// テーブル作成(プラグイン有効化時または初回実行時)
function create_mail_log_table(): void {
global $wpdb;
$table = $wpdb->prefix . 'mail_log';
if ($wpdb->get_var("SHOW TABLES LIKE '$table'") === $table) return;
$wpdb->query("CREATE TABLE $table (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sent_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
recipient VARCHAR(255) NOT NULL,
subject VARCHAR(500) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'sent',
INDEX (sent_at)
) " . $wpdb->get_charset_collate());
}
add_action('init', 'create_mail_log_table');
// 送信成功を記録
add_filter('wp_mail', function(array $args): array {
add_action('phpmailer_init', function() use ($args): void {
global $wpdb;
$wpdb->insert($wpdb->prefix . 'mail_log', [
'recipient' => is_array($args['to']) ? implode(',', $args['to']) : $args['to'],
'subject' => $args['subject'],
'status' => 'sent',
]);
});
return $args;
});
// 直近100件のログを表示(管理画面ページに追加可能)
function get_recent_mail_log(int $limit = 100): array {
global $wpdb;
return $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}mail_log ORDER BY sent_at DESC LIMIT %d",
$limit
)
);
}
ステップ4:外部SMTPに切り替えてスパム送認証を強化する
// functions.php: Gmail SMTP / SendGrid に切り替え
// 推奨プラグイン: WP Mail SMTP (wp plugin install wp-mail-smtp)
// または手動設定(SMTPクレデンシャルは wp-config.php に定義)
// wp-config.php に追加:
// define('SMTP_HOST', 'smtp.sendgrid.net');
// define('SMTP_PORT', 587);
// define('SMTP_USER', 'apikey');
// define('SMTP_PASS', 'your-sendgrid-api-key');
add_action('phpmailer_init', function(PHPMailer\PHPMailer\PHPMailer $phpmailer): void {
if (!defined('SMTP_HOST')) return;
$phpmailer->isSMTP();
$phpmailer->Host = SMTP_HOST;
$phpmailer->SMTPAuth = true;
$phpmailer->Port = SMTP_PORT;
$phpmailer->Username = SMTP_USER;
$phpmailer->Password = SMTP_PASS;
$phpmailer->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
$phpmailer->From = get_option('admin_email');
$phpmailer->FromName = get_bloginfo('name');
});
ステップ5:異常な送信を検知してアラートを送る
// functions.php: 送信急増を検知して管理者に通知
add_action('wp_mail', function(): void {
$key = 'mail_spike_' . date('YmdHi'); // 1分単位
$count = (int) get_transient($key);
$count++;
set_transient($key, $count, MINUTE_IN_SECONDS * 2);
if ($count === 10) { // 1分間に10通で警告
$admin = get_option('admin_email');
$msg = sprintf(
"サイト %s で1分間に%d通のメールが送信されました。\n送信元を確認してください。\n\n%s",
home_url(),
$count,
date('Y-m-d H:i:s')
);
// wp_mail を使わず直接送信(ループ回避)
mail($admin, '[警告] メール送信急増を検知', $msg);
}
});
注意事項
wp_mailフィルターで$args['to']を空にするとメール送信はキャンセルされますが、送信失敗エラーはログに出力されます- 外部SMTPを使用する場合、送信ドメインのSPF/DKIM/DMARCレコードをDNSに設定するとスパム判定を回避しやすくなります
- メールログテーブルは定期的に古いレコードを削除する保守処理も実装してください(30〜90日保持推奨)
まとめ
メール送信制限は①mailqと/var/log/mail.logで現状把握、②wp_mailフィルターでトランジェントを使った1時間あたり送信数カウント・上限超過で受信者を空にしてブロック、③カスタムテーブルへの全送信ログ記録、④SendGrid/GmailへのSMTP切り替えでSPF/DKIM認証を確立、⑤1分間に10通超えでmail()関数を直接使って管理者にアラートを送る仕組みで多層防御します。