PHP 获取超过 20000 封 imap 电子邮件
Posted
技术标签:
【中文标题】PHP 获取超过 20000 封 imap 电子邮件【英文标题】:PHP fetch over 20000 imap emails 【发布时间】:2013-02-16 11:00:36 【问题描述】:我正在尝试将多个邮箱导出到数据库。我当前的脚本将连接 IMAP 并循环所有消息。尽管对于较大的邮箱,这将不起作用,并且会减慢甚至停止。
我们的想法是每天运行脚本以将尚未在数据库中的所有消息“复制”到数据库中。获取大量电子邮件的最佳方式是什么(20k 封邮件分布在大约 40 到 50 个文件夹中)。
最终,这将需要在单个服务器上进行,以每天扫描数百甚至数千个帐户(想象一下数据量)。它将邮件(uid 和主题)存储到数据库中,并创建一个将存储在数据服务器上的包(因此它还需要获取附件)。
【问题讨论】:
【参考方案1】:你在用imap_ping
吗?
imap_ping() ping 流以查看它是否仍然处于活动状态。有可能 发现新邮件;这是定期“新 邮件检查”以及“保持活动”的服务器有 不活动超时。
其他要查看的:imap_timeout
imap_reopen
事实上有一个名为reopen
的方法暗示了一些事情不是这样的:)
如果您似乎无法保持连接,另一个选择是将数据导出为mbox
格式并在本地获取。对于大型邮箱可能会更快,并且可以消除超时/连接问题。
【讨论】:
它必须能够连接多个不同的服务器,所以很遗憾,本地不是一个选项。这个想法是一次获得所有“新”电子邮件。但是我怎么能确定没有再次循环(并检查它们是否存在于数据库中)它们呢? 啊,这很容易 IMAP 有一个“已看到”标志,对吧?另外,应该有一个序列...msgno
?或者,将电子邮件转发到您可以处理并在处理后删除的存档中。您描述了 IMAP 的一个常见用例。
邮箱只会被“归档”到数据库中,所以看不见/看见的标志不起作用。
imap_fetch_overview
的第二个参数... 消息序列描述。您可以使用 X,Y 语法枚举所需的消息,或使用 X:Y 语法检索间隔内的所有消息。如果您无法使用开箱即用的功能执行您所描述的操作,您会感到惊讶。【参考方案2】:
所以您想通过 IMAP 执行电子邮件备份。有专业的软件工具可以做到这一点。
让我们从简单的事情开始:从收件箱文件夹中为特定用户下载一封电子邮件。这需要您 (a) 使用用户的凭据登录,(b) 选择收件箱文件夹,以及 (c) 下载消息(假设您已经知道它的 UID,即 55)。您在 IMAP 中按如下方式执行此操作(仅限请求 - 未显示响应):
01 LOGIN username password
02 SELECT INBOX
03 UID FETCH 55 BODY[]
特定文件夹中的每条消息都被赋予一个UID。这是永远不会更改的消息的唯一标识符 - 该文件夹中的任何其他消息都不能使用它。新消息的 UID 必须高于以前的消息。这使它成为确定您之前是否已经下载过邮件的有用工具。
下一步:现在让我们看看下载收件箱文件夹中的所有新邮件。假设您是第一次下载消息,而收件箱当前有 UID 为 54、55 和 57 的消息。您可以使用以下命令一次性下载这些消息:
03 UID FETCH 54,55,57 BODY[]
(如果有很多要下载的内容,您可能希望分批拆分(例如一次 30 个)。)完成此操作后,您将存储迄今为止下载的最高 UID。下次,您可以检查是否有高于此的 UID,如下所示:
04 UID FETCH 58:* UID
这将(仅)检索 UID 从 58 开始的消息的 UID。如果得到结果,则下载这些结果,然后再次存储 UID。以此类推。
有一个问题。只要文件夹的 UIDVALIDITY 属性(包括在对 SELECT 命令的响应中)不更改,消息的 UID 就有效。如果由于某种原因发生更改,该文件夹将失效,您需要重新下载该文件夹中的所有邮件。
最后,您希望将此扩展为适用于所有用户的所有文件夹。为了获取特定用户的所有文件夹,您可以使用 IMAP LIST 命令:
05 LIST "" "*"
您需要事先知道用户的凭据并遍历它们。
这是您需要做的事情背后的 IMAP 理论。在 php 中实现它留作练习。
【讨论】:
我可以像 cronjob 一样分批下载它们,每分钟运行一次并检查是否有批处理要处理。虽然我的应用程序需要检查超过 1k - 5k IMAP 框并每天至少检索一次所有新邮件。假设 IMAP 框平均有大约 10k 条消息分布在 50 个文件夹中,那么导入将需要很长时间?有什么办法可以用 PHP 加快速度吗?将 cronjob 提高 25 倍(启动所有 @ 不同的框)会将过程加快 25 倍吗? 您想要下载大量数据,您将不得不处理这些限制。毫无疑问,您会受到可用处理能力和带宽的限制......所以您可以尝试一些优化(就像您提到的,并行运行任务),但您仍然会在某个时候达到限制而不是能够进一步加快速度。我建议更定期地运行小型作业(而不是每天一次),这样下载量相对较小且增量。 另外,我假设您指的是 10k 条消息,指的是所有消息的首次下载。是的,这将需要相当长的时间。但是,您仍然会受到资源的限制。也许有多台机器同时归档不同的帐户。 不,所有电子邮件都必须有一个符合 RFC3501 的 UID。散列不是最好的方法......特别是如果你没有考虑到身体。两条不同的消息有可能(尽管在统计上不太可能)解析为相同的哈希 - 这称为冲突。 如果用户从一个文件夹中删除所有消息,那么 UID 仍然会比之前的 UID 大(请参阅对 SELECT 的响应中的 UIDNEXT)。当您移动消息时,您不会以我们理解的在硬盘上移动文件的方式移动消息。客户端通过将消息从文件夹 A 中删除并将其附加到文件夹 B 来移动消息。以上是关于PHP 获取超过 20000 封 imap 电子邮件的主要内容,如果未能解决你的问题,请参考以下文章
从 Gmail API 批量获取超过 10k 封电子邮件的电子邮件发件人
android 邮件服务器,全球邮企业邮箱Android(安卓)系统手机 POP3 IMAP协议设置方法
使用 python imaplib 从 Gmail 中“删除”一封电子邮件?