通过PHP向许多用户发送邮件的安全方式

Eug*_*ene 10 php mysql email e-commerce

让我解释一下我在标题中的含义.让我们说,例如,我正在为一个网上商店/目录创建一个小型电子商务系统.客户有可能选择,他们是否希望收到新闻通讯.如果他们这样做,那么逻辑上应该立即发送新闻通讯,因为新闻通讯已经形成并准备就绪.

当然,它可以通过从数据库中获取所有指定的用户电子邮件并使用for循环通过mail函数循环发送邮件来完成,但问题是我被告知,这是不好的做法.简单而不便宜的方式是购买发送新闻通讯的互联网服务,但是对于php程序员需要什么呢?

所以我问你们谦虚的同志,你们的观点可能是什么解决方案?

NB!你可能不会相信我,但它不是垃圾邮件.

UPD:我可能已经解释错了,但我想听到的解决方案不仅是关于正确的发送邮件的方式,还有正确的交付方式.因为不是每个邮件发送总是交付.
当然有一些原因是不可预测的.例如,某个地方出现了故障并且邮件丢失(如果可能的话),但也有其他原因可能会受到服务器或其他地方的影响.也许需要与托管人讨论这个问题?

Wri*_*ken 26

没有理由不能用PHP编写它,尽管我不会将它作为webrequest/HTTP进程的一部分.我已成功实施每个邮件给予或接受500,000个订阅者(取决于可用的本地数据,因为这是一个特定于位置的项目).这是一个内部项目,很遗憾没有代码/包,但我遇到了一些指示:

设置交货

  • 开始使用phpmailer本身,以处理格式化,内容和标题的编码,添加附件等.它的一部分工作得很好,我不想从头开始编写.
  • 电子邮件本身的"发送"只是在数据库中设置一些标志是否/如何/应该发送给(部分)订户.
  • 设置此标志后,它将自动被cronjob拾取,不再涉及网络服务器.
  • 我从一个污染严重的数据库开始,有数百万个电子邮件地址,其中很多都显然无效,所以首先要验证格式的所有电子邮件地址,然后是主机:
    • filter_var($email, FILTER_VALIDATE_EMAIL); 在订阅者(并显然存储结果)摆脱了前几十万个无效的电子邮件.
    • 从电子邮件中拆分主机(并存储主机名),并验证它(在DNS中是否有MX或至少A记录,但请记住:您可以向IP地址发送电子邮件foo@[255.255.255.255],所以保持那些有效))更多地摆脱了很多.此处的电子邮件地址不是永久禁用的,但有一个状态标志,表示由于域名/ IP而被禁用.
    • 脚本被更改为在订阅/插入之前需要有效的电子邮件地址,这无关紧要的"你不会得到它@任何地方"订阅 - 数据库中的污染只是荒谬.
  • 现在我最终得到了一个有可能有效的电子邮件地址列表.实质上有3种方法可以检测无效地址(请记住,所有地址可以是临时的):
    • 它们立即被服务器拒绝.
    • 早先确定的服务器只是不听流量.
    • 在你认为你交付它们之后很久就会被弹回.
  • 奇怪的是,反弹,每个电子邮件服务器似乎都有另一种格式,最初解析起来很难解决,最后使用VERP很容易捕获.而不是解析整个电子邮件,一个专用的电子邮件地址(我们称之为mailer@example.com)配置为而不是传递到邮箱,管道它通过一个命令,如果我们发送的电子邮件,以user@server.tld的Return-Path是为...设置mailer+user=server.tld@example.com.在收据上轻松解析,并且在多少跳出(邮箱不存在,邮箱可能已满(是的,仍然!)等)之后,您声明电子邮件地址无法使用取决于您.
  • 现在,由服务器直接拒绝.可能我们可以为这些配置正确配置一些MTA和/或编写插件,但由于电子邮件是时间敏感的,我们必须在最后一次可用的交付时间内对每个邮件进行绝对可配置的控制(之后电子邮件不再是对于用户感兴趣的),每个接收服务器的限制,以及通常所有的东西,大约需要花费大约相同的时间在PHP中编写一个我们更清楚的邮件程序,它将SMTP协议直接用于接收服务器上的套接字25.只需花费最少的精力就可以进行另一次传输,然后内置PHPMailer中的默认选项.SMTP协议实际上非常简单,但有一些警告:
    • 许多接收服务器应用灰色列表:大多数垃圾邮件不会真正关心特定邮件是否到达,他们只是简单地说出来.因此,如果未知/尚未信任的发件人发送邮件,它将被暂时拒绝.捕获(通常是代码451),并将电子邮件放入队列中以供稍后重试.
    • 邮件服务器,特别是大型ISP和免费服务(gmail,hotmail/msn/live等)的邮件服务器不会代表大量邮件而不会反击:在前几百/千之后,他们开始拒绝你.稍后会详细介绍.

获得速度

  • 现在,我们有一个有效的交付系统,但它需要快速.如果您只有10,000个地址要发送,那么在一小时内发送10,000封电子邮件就可以了,但我们要求的最低数量是每小时约200,000封.它的开始是一个专用服务器(实际上可能是非常低功耗的,无论你做什么,交付电子邮件的大部分时间都在网络中,而不是在你的服务器上).
  • IP的缓存:记住我们从电子邮件地址中的主机名请求的所有IP吗?我们显然存储了这些,并且一次又一次地查找他们的IP会造成相当大的滞后.但是,IP可能会发生变化:那里有DNS记录,另一个地方有另一个MX ......数据变得陈旧.大多数情况下,服务器实际上并没有发送任何东西(订阅新闻报道明显突然出现),低优先级的cronjob正在运行检查所有主机名,其中包含过时的IP(我们选择较旧的,然后1天作为过时)用于IP地址,包括以前没有的那些(新域名一直在注册,所以为什么在有人已​​经热情地订阅了他/她的全新电子邮件地址后的某一天,域名不可用?或者某些域名的服务器问题已经解决,等等).实际上发送电子邮件现在不再需要域查找.
  • 重新使用SMTP连接:当您直接与端口25通信时,建立与服务器的连接需要相当大的时间来发送电子邮件.您不必为每封电子邮件设置新连接,可以通过相同的连接发送下一个.一些跟踪和错误导致在此设置默认值为每个连接约50封电子邮件(假设您拥有该域的许多或更多).但是,如果关闭电子邮件地址失败并重新开启重试连接,有时会有所帮助.总而言之,这确实有助于加速发展.
  • 一些明显的一个,所以很明显我差点忘了提到它:它会是一种浪费必须创建当场电子邮件正文:如果它是一个普通的邮件,有身体准备好(我改变PHPMailer的有点是能够使用缓存的电子邮件),可能是前几天(如果你知道你要发送的邮件上周五,和你的服务器空闲的,为什么不能在周三做好准备了吗?如果它的个性化,你仍然可以准备事前给予足够时间,如果没有,至少有非个性化部分等待去.
  • 多个过程.我是否提到过将电子邮件花在网络上的大部分时间?一个邮件流程几乎没有从您的电子邮件服务器中获得最大收益,几乎没有明显的负载,而且邮件正在逐渐消失.通过邮件队列的不同部分的多个进程来查看什么是适合您的服务器/连接,但请记住2个非常重要的事情:
    • 不同的流程让你非常容易受到竞争条件的影响:绝对确定你有一个完整的系统,永远不会发送两次相同的邮件(三次,甚至更多).它不仅严重惹恼了用户,而且垃圾邮件也在不断上升.
    • 尽可能将域保持在一起:从队列中随机选择,您将失去与接收域的电子邮件的服务器保持开放连接的优势.

避免拒绝

  • 你要发送很多邮件.这正是垃圾邮件发送者所做的.但是,你不希望被视为垃圾邮件发送者(毕竟,你不是,是吗?)有许多机制可以彻底提高您对接收服务器的可信度:
  • 有一个适当的反向DNS:过程检查属于正在发送的电子邮件,如IP的DNS它非常如果第二级域匹配了:你代表发送邮件example.com?确保您的服务器的反向DNS类似于somename.example.com.
  • 发布域的SPF记录:明确指出允许发送批量电子邮件的计算机以及预期使用该From/Return-Path标头发送邮件.
  • 记住拒绝:服务器不喜欢它一次又一次地告诉你不存在不同的电子邮件地址.自动化机制,甚至是人工管理员,在我们处理完所有(不再存在)的所有未经验证的电子邮件地址时阻止了我们的服务器.我们之前没有使用双重选择,所以数据库被打字错误,人们切换IP,从而电子邮件地址,恶作剧电子邮件地址等等.一定要捕获那些残留物,并给予足够或足够严重的故障,取消订阅它们.他们对你没有好处,他们正在占用资源,如果他们真的想要你邮件,邮箱后来可以使用,他们只需要重新订阅.
  • DKIM是另一种可能提高您可信度的机制,但由于我们还没有实现它,我不能告诉你太多.
  • MX记录:如果您的发送服务器也是域的接收服务器,某些服务器仍然喜欢它.就像当时一样,我们只有1个MX,并且由于邮件服务器仍然不是那么繁忙,我们称之为域的后备MX服务器.普通的MX服务器不是发送订阅的服务器,因为您尝试向(客户端等)发送重要电子邮件的服务器暂时阻止它是非常恼人的,因为您已经发送了一堆不太重要的邮件.它确实具有接收MX的最高优先级,但是如果它失败了,我们有一个很好的奖金,我们的订阅发送服务器仍然会回落交付,所以在危机中我们仍然可以得到它,防止尴尬的反弹给客户尝试联系我们
  • 告诉他们你的情况.认真.许多像live.com这样的免费电子邮件地址的主要参与者为您提供了以某种方式注册的机会,或者如果您的电子邮件被拒绝,请联系我们寻求帮助和支持.我有合理的理由发送这么多电子邮件,而且你有很多订阅者是可信的,他们很可能会认真地提高你每小时可以发送到他们服务器的电子邮件数量.如果你足够有说服力和诚实,那么1000美元甚至可能会变成一万或更高.可能存在合同,您必须履行的要求,以及您必须允许(并保持)允许的承诺.互联网服务提供商是一个独立的品牌,每个其他玩家都是不同的.通常不打扰他们,因为99%的时间你可以找到的唯一数字只会让人愿意解决你的互联网连接问题,而这些连接理解(或被允许)其他的东西.一个abuse@电子邮件地址是一个很好的起点,但看看你是否可以从某个地方钻取更多的电子邮件地址.准确,诚实和完整:大约有多少订阅者与ISP建立了电子邮件地址,您多久发邮件一次,收到的错误或拒绝是什么,订阅和取消订阅过程如何,以及什么是您实际提供给客户的服务.此外,要好一点:发送这些邮件可能对您的业务至关重要,对此感到恐慌并声称可怕的损失与他们无关.对事实和愿望的礼貌陈述,以及询问他们是否可以提供帮助,而不是要求解决方案,这需要很长的路要走.
  • 限制:尽管您尝试过,但某些服务器每小时和/或每天只接受一定数量的邮件.学习这些数字(我们无论如何都要记录成功和失败),将它们设置为正常域的合理默认值,将它们设置为对更大的玩家的约定.

避免被标记为垃圾邮件

  • 第一条规则:不要垃圾邮件!
  • 第二条规则:永远!不是'一次性',不是'他们没有订阅,但这可能是他们一辈子的交易',而不是最好的意图,人们不得不要求你的电子邮件.
  • 显然建立了正确的双重选择订阅机制.
  • PHPMailer自己设置了合适的头文件,
  • 通过网络设置一个简单的取消订阅机制(包括封邮件中的链接),如果有的话,可能还有电子邮件和客户服务.确保客户服务可以直接取消订阅.
  • 如前所述:取消订阅(过度)失败和反弹.
  • 避免垃圾邮件"终身交易"的措辞.
  • 谨慎使用电子邮件中的网址.
  • 避免添加指向您无法控制的域名的链接,除非您绝对相信他们可以信任他们不要发送垃圾邮件,即使这样......
  • 为用户提供价值:在google/yahoo/live webmail客户端通过用户交互标记为垃圾邮件会严重损害未来的成功(在网站上注意:如果您注册,live/msn/hotmail会将所有邮件转发给您由您的域名发送,被用户标记为垃圾邮件.学会喜欢它,并一如既往:取消订阅,他们显然不想要您的商城,并且正在损害您的垃圾邮件评级).
  • 监控您的IP黑名单.如果您出现在其中一个上,那就是再见,所以需要清除您的姓名确定案件的立即行动.

衡量成功率

  • 在整个过程由您控制的情况下,您可以合理地确定电子邮件在某个地方结束(尽管它可能是MX的bitbucket或垃圾邮件文件夹),或者您已记录失败及其原因.这照顾了"实际交付"的数字.
  • 有些人会试图说服您将在线图像链接添加到您的电子邮件(真实或着名的1x1透明gif),以衡量实际阅读电子邮件的人数.由于高百分比阻挡这些图像,这些数字最多是不稳定的,我们相信我们不应该打扰他们,他们的数字是完全不可靠的.
  • 如果您希望用户做某事,那么衡量实际成功率的最佳选择就容易多了.将参数添加到邮件中的链接,以便您可以衡量到达您链接的网站的用户数量,是否执行了所需操作(观看视频,留下评论,购买商品).

总而言之,所有日志记录,用户界面,每个域/电子邮件/用户等的可配置设置.我们花了大约1.5个人月来构建和消除这些怪癖.与外包电子邮件相比,这可能是一项相当大的投资,可能不是,这完全取决于数量和业务本身.

现在,让火焰开始让我在PHP中编写MTA是一个傻瓜,我非常喜欢它(这是我编写大量文本的一个原因),以及极其通用的日志记录和设置功能,每个主机基于故障百分比等的警报正在生效哦这么容易;)


Rus*_*ias 6

使用像Swiftmailer,PHPmailerZend_mail这样的东西是使用简单mail()功能的更好的替代方法,因为它可以很容易地标记为垃圾邮件.邮件中存在太多需要考虑的问题 - 大多数问题都是通过使用预先存在的库来解决的.

手动发送群发电子邮件时需要解决的几个问题:

  • 使用错误的标题.

  • 处理退回邮件

  • 由于电子邮件的涌入而导致脚本失效.

编辑:

可能不是你想要的答案.但是,我强烈建议你投资一些像Campaign MonitorMail Chimp这样的东西.由于这个过程不是出于教育目的,而是出于商业目的,我强烈建议上述服务.