3

我有一个大约有一个 Web 应用程序。30k 用户并快速增长。我们希望通过电子邮件启用某些功能,这意味着为每个用户分配一个唯一的电子邮件地址(出于安全原因)。发送到这些唯一地址的电子邮件应转发到 PHP 脚本。PHP 脚本需要访问电子邮件的所有部分——标题、正文和任何附件。我不确定设置它的正确方法是什么。我们目前正在使用 sendmail 并且更愿意坚持使用它(这是 linux,如果重要的话)。我已经能够将单个电子邮件转发到脚本,但是(在我看来)创建 30k 别名然后每次新用户注册时创建一个新别名是不可扩展的。我会更喜欢某种类型的包罗万象/基于 RegEx 的解决方案,它只是告诉 PHP 脚本作为收件人的唯一电子邮件地址,

4

3 回答 3

7

30k 帐户不会向我们提供有关您希望处理的流量的任何信息。但让我们假设这是另一个问题。

您可以创建catch all帐户类型,它只会接受您在其中创建用户地址的域中的任何电子邮件(基本上*@domain)。然后您可以在每封传入邮件上启动您的处理脚本(您通常可以从stdin流中获取整个邮件正文(在 PHP 中可通过 访问php://stdin),并根据需要进行处理。但是如果您想使用 PHP(或几乎任何脚本语言),因为每封邮件都需要生成新的 PHP 进程,初始化所有扩展等等。这一切都需要时间和资源,而且更大的垃圾邮件泛滥,你的盒子几乎被烤熟了。

或者,您可以将您的邮件作为任何其他邮件收集在邮箱中,然后让您的脚本从那里获取它(直接挖掘maildir或通过 IMAP 或 POP 等邮件协议)。从管理的角度来看,这看起来更好,只要您的邮件服务器可以接受传入的邮件,您的整个系统仍然可以工作。您甚至可以尝试通过设置一些过滤规则(在 MTA 级别)来“分区”您的系统,并将传入的邮件发送到单个邮箱而不是更多邮箱。然后,您可以更轻松地并行处理这些邮件(无需费心处理具有多个实例的相同邮件等)。“分区”模式可以是任何东西,即取决于您的完整地址命名方案,如果基于字母,它将是单独的邮箱a*@b*@或者[a-d]*@](取决于交通),并不重要。

或者,您可以尝试将传入邮件的正文放入数据库,然后如上所述进行处理,而不需要任何 POP/IMAP 处理。

无论您选择什么,我建议您不要将任何形式的处理脚本直接放在邮件接收流程链中。延迟 1 分钟通常不是问题(因此您可以运行任何类型的守护进程并获取邮件进行处理、cronjob 等),用户可以等待那么久而不会抱怨 - 看起来即时处理很可能不会在您的情况下也是强制性的。但如果是这样,那么恐怕 PHP可能不是最好的工具选择。

编辑:(回答评论问题而不是达到评论大小限制)

我对 Sendmail 不够熟悉,无法在这里为您提供精确的配置指令(我在定制的 qmail 上),但我希望有一些一般性的提示适用。首先,我相信 Sendmail 支持虚拟用户(这意味着邮箱中不存在的用户/etc/passwd)。如果是这样,那么 MTA 通常应该让您使用一些内置提供商查询 DB(以查明目标电子邮件地址是否有效以及该用户的主目录在哪里放入邮件)。或者(甚至更好)调用外部程序来做到这一点。后者在这里是赢家,因为实际上没有用户,因此您可以编写小脚本或(再次,性能更好)C 应用程序来解决问题。由于您所需要的只是根据一些简单的预定义规则将传入的邮件“分离”到几个物理邮箱中,所以几个if()s +substr()s,你就完成了。几行,不需要数据库,很快。或者,更好的是,您甚至可以在roundrobin这里尝试最愚蠢的方法 - 实际上,如果邮件命中accountAaccountB只要 50% 的邮件以 50% 的结尾A和其他 50%的结尾B(或者如果您选择 4 个目标帐户,则为 25%等),这是我认为你应该关心的唯一条件。您可以尝试使用procmail它,但我认为它没有意义,并且对性能不是最好的。

至于将邮件放入数据库。这取决于 MTA - 默认情况下没有人这样做,因为它比将邮件放入 maildirs 慢(因为 DB 通常是其他主机),但仍然有几个解决方案。要么为 Sendmail 寻找第三方补丁,要么添加另一个脚本/应用程序,将邮件从物理邮箱“复制”到数据库中。你可能会说 - 但它会更慢。当然,但同样 - 我不知道非实时处理在你的情况下是否真的很重要(我的盲目猜测 - 它没有),所以为什么要打扰。如果您在这里节省了几毫秒,但在整个解决方案的进一步维护上花费了几分钟,那么选择就很明显了。

顺便说一句:以防万一——每当我写的时候,mailbox我肯定是指用户邮件的容器,而不是 mailbox文件格式。至于文件格式maildir(或其他东西)是更好的选择。

于 2012-09-10T17:22:55.890 回答
1

你真的想为每封收到的电子邮件分叉一个 PHP 吗?如果您要处理体面的邮件量,那可能会变得昂贵。为什么不在邮件服务器中使用自定义回调来处理传入邮件并插入数据库,然后使用工作脚本不断轮询要处理的新邮件?

mail-to-db 部分应该比所有处理都轻得多,这为您提供了一个空闲队列,因此如果您几乎同时收到一堆请求,您的系统不会在尝试处理时崩溃他们一下子。

于 2012-09-10T15:53:46.840 回答
1

做了一个类似的实现,虽然规模较小......但应该扩展以满足您的目的。

两个单独的问题

(1) 邮件 - 前面提到的包罗万象是一个很好的解决方案,尽管您将不得不处理垃圾邮件和格式错误的电子邮件地址(这可能是好事也可能是坏事)。如果您拥有服务器,只需为“虚构”帐户设置别名并指示邮件服务器将它们全部放入同一个中央邮箱即可完成任务,因为您不需要单独的实际帐户,并且标题信息将保持不变。具体取决于您的邮件解决方案,但任何邮件服务器都应该具备处理此任务和卷的能力,并且您应该能够编写别名创建脚本......否则返回包罗万象

(2) PHP解析处理——PHP内置的pop3函数可以轻松处理查看(现在的)单个邮箱账户和处理消息;我曾经经历过的一些功能示例是:

function pop3_login($host,$port,$user,$pass,$folder="INBOX",$ssl=false){
        $ssl=($ssl==false)?"/novalidate-cert":"";
        return (imap_open("{"."$host:$port/pop3$ssl"."}$folder",$user,$pass,OP_SILENT));
}
function pop3_stat($connection){
        $check = imap_mailboxmsginfo($connection); # changed from $imap
        return ((array)$check);
}
function pop3_retr($connection,$message,$section='1'){
        return(quoted_printable_decode(imap_fetchbody($connection,$message,$section)));
}
function pop3_dele($connection,$message){
        return(imap_delete($connection,$message));
}
function pop3_close($connection){
        return(imap_close($connection,CL_EXPUNGE));
}

一切都非常通用,如果您不需要控件,可能会有类。最重要的是,PHP 拥有快速解析和处理邮件消息所需的一切。

于 2012-09-14T19:49:50.023 回答