You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cpanel中Pipe to Program邮件转发重复问题求助

问题描述

我们用Cpanel的「Pipe to Program」功能做邮件转发,转发规则如下:

邮箱地址转发目标
email.1@domain.com|/home/user/forwarder/forward.php
email.2@domain.com|/home/user/forwarder/forward.php

对应的forward.php脚本逻辑:

#!/usr/bin/php -q
<?php
$forwarders = [
    'email.1@domain.com' => ['email.1@gmail.com'],
    'email.2@domain.com' => ['email.2@gmail.com']
];

$recipients = $parseHeader['to'];
$to = [];
foreach($recipients as $recipient){
    if(isset($forwarders[$recipient])){
        foreach($forwarders[$recipient] as $forwarder){
            $to[] = $forwarder;
        }            
    }
}

//Send one email with emails in $to

当邮件同时发送到email.1@domain.com和email.2@domain.com时,脚本生成的$to数组包含两个目标邮箱,但实际每个目标邮箱会收到2份相同邮件(3个收件人则收到3份)。

问题根源

邮件同时发给多个触发Pipe规则的邮箱时,Cpanel会为每个收件人单独触发一次脚本执行:

  1. 邮件发送到email.1@domain.com和email.2@domain.com
  2. 触发email.1@domain.com的转发规则,脚本执行并向两个目标邮箱发邮件
  3. 同时触发email.2@domain.com的转发规则,脚本再次执行并向两个目标邮箱发邮件
    最终每个目标邮箱收到多次重复邮件。
解决方案

方法1:让脚本只处理当前触发它的收件人(推荐)

Cpanel调用Pipe脚本时,会把当前触发的邮箱地址通过命令行参数$argv[1]传递给脚本。直接用这个值获取对应的转发目标,不用解析所有收件人。

修改后的forward.php:

#!/usr/bin/php -q
<?php
$forwarders = [
    'email.1@domain.com' => ['email.1@gmail.com'],
    'email.2@domain.com' => ['email.2@gmail.com']
];

// 获取当前触发脚本的收件人(Cpanel传递的参数)
$currentRecipient = $argv[1] ?? '';
$to = [];

if(isset($forwarders[$currentRecipient])){
    $to = $forwarders[$currentRecipient];
}

// 只向当前收件人对应的目标邮箱发送邮件
if(!empty($to)){
    // 执行邮件发送逻辑,比如用mail()或PHPMailer
}

这样每次脚本执行只处理触发它的那个邮箱对应的转发目标,从根源避免重复发送。

方法2:通过邮件唯一标识避免重复

如果需要保留解析所有收件人的逻辑,可以利用邮件的Message-ID(每个邮件的唯一标识),记录已处理过的ID,避免重复执行发送操作。

示例代码片段:

#!/usr/bin/php -q
<?php
// 从标准输入读取邮件头,提取Message-ID
$messageId = '';
$fd = fopen("php://stdin", "r");
while (!feof($fd)) {
    $line = fgets($fd);
    if(trim($line) === '') break; // 邮件头结束
    if(strpos($line, 'Message-ID:') === 0){
        $messageId = trim(str_replace('Message-ID:', '', $line));
        break;
    }
}
fclose($fd);

// 记录已处理Message-ID的文件路径
$processedIdsFile = '/home/user/forwarder/processed_ids.txt';
$processedIds = file_exists($processedIdsFile) ? file($processedIdsFile, FILE_IGNORE_NEW_LINES) : [];

// 该邮件已处理过,直接退出
if(in_array($messageId, $processedIds)){
    exit;
}

// 执行原有的转发逻辑
$forwarders = [
    'email.1@domain.com' => ['email.1@gmail.com'],
    'email.2@domain.com' => ['email.2@gmail.com']
];

$recipients = $parseHeader['to'];
$to = [];
foreach($recipients as $recipient){
    if(isset($forwarders[$recipient])){
        foreach($forwarders[$recipient] as $forwarder){
            $to[] = $forwarder;
        }            
    }
}

// 发送邮件
// Send one email with emails in $to

// 记录已处理的Message-ID
file_put_contents($processedIdsFile, $messageId . PHP_EOL, FILE_APPEND);

注意:定期清理processed_ids.txt,避免文件过大占用空间。

方法3:合并转发规则

如果多个邮箱的转发逻辑完全一致,可以把所有需要转发的邮箱合并到一个规则里:

  • 创建一个统一的中转邮箱,比如forward-all@domain.com
  • 把email.1@domain.com和email.2@domain.com都转发到这个中转邮箱
  • 只为中转邮箱设置Pipe规则到脚本
    这样不管多少个收件人,只会触发一次脚本执行,彻底避免重复。

内容的提问来源于stack exchange,提问作者john

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:29:52