【问题标题】:error while trying to send bulk emails using ruby尝试使用 ruby​​ 发送批量电子邮件时出错
【发布时间】:2019-01-13 17:14:43
【问题描述】:

我正在尝试使用 ruby​​ 脚本发送一些电子邮件,但在发送到大约几封电子邮件后出现错误,然后给出如下所示的错误。注意:我使用 office365 作为 smtp 提供程序。 这是包含以下脚本的初始文件夹 folder containing the scripts

这是下面的电子邮件处理程序脚本

require './savmail/lib/mail.rb'

require './utils.rb'

RECIPIENT_HOLDER = "%0%"

module EmailHandler
    def self.format_email(email: '', recipient: '')
        # fill in all the placeholders
        return email.gsub(RECIPIENT_HOLDER, recipient)
    end


    def self.compose_email(recipient: nil, sender: nil, sender_name: nil, subject: '', html: nil, text: '')
        # Save recipient so other threads don't touch
        Utils.save_recipient(email: recipient)
        text_content = text
        html_content = format_email(email: html, recipient: recipient)

        mail = Mail.new do
            to      recipient
            from    sender_name + " <" + sender + ">"
            subject subject
        end

        text_part = Mail::Part.new do
            body text_content
        end

        html_part = Mail::Part.new do
            content_type 'text/html; charset=UTF-8'
            body html_content
        end

        mail.text_part = text_part
        mail.html_part = html_part

        return { 'msg'=> mail, 'recipient'=> recipient, 'sender'=> sender }
    end

    def self.email_login(sender_tuple: [], mail: '')
        smtp_login = sender_tuple[0]
        smtp_password = sender_tuple[1]
        smtp_host = sender_tuple[2]
        smtp_port = sender_tuple[3]
        limit = sender_tuple[4]

        begin
            # server = smtplib.SMTP(smtp_host, smtp_port)
            # server.starttls()
            # server.login(smtp_login, smtp_password)
            options = { 
                :address              => smtp_host,
                :port                 => smtp_port,
                # :domain               => 'your.host.name',
                :user_name            => smtp_login,
                :password             => smtp_password,
                :authentication       => 'login',
                # :enable_starttls_auto => true  
            }
            mail.delivery_method :smtp, options

            return mail
        rescue Exception => e
            puts 'Failed to Login to ' + smtp_login
            return false
        end
    end

    def self.send_email(payload: nil, sender_address: nil, recipient: nil, server: nil)
        begin
            payload.deliver
            puts 'Sent from '+sender_address+' to '+recipient
            return payload
        rescue Exception => e
            Utils.save_recipient(email: recipient, failed: true)
            puts 'Email Failed to Send from '+sender_address+' to '+ recipient
            return false
        end
    end
end

那么这是主要的发送者脚本

# from email_handler import compose_email, send_email, email_login
require './email_handler.rb'
require './utils.rb'
include EmailHandler

# Change Subject for all emails here
$custom_sender_name = "Africonso Tradings"
$custom_sender_email = "admin@africonsotradings.com"
$email_subject = "test mail."
$threads_total = 10

# These files have to exist
$army_file_path = './army.txt'
$email_file_path = './msg.html'
$senders_file_path = './senders.txt'


def mail_savage(recipients, senders, payload, custom_sender_email, custom_sender_name, email_subject, active_limit: nil, active_server: nil)
    ''' Login as one sender and send emails until the limit is reached or the email stops working,
    then do the same for the rest
    '''
    # Get first recipient from array
    sender = senders[0]

    # sender_email, smtp_password, smtp_host, smtp_port, limit = sender
    sender_email = sender[0]
    smtp_password = sender[1]
    smtp_host = sender[2]
    smtp_port = sender[3]
    limit = sender[4]
    mail_limit = active_limit or limit.to_i

    # if !recipients
    #     return true
    # end

    # Make sure we haven't emailed this user before
    for recipient in recipients
        if Utils.is_recipient_saved(email: recipient)
            # Move to next email if sent already
            next
        end

        # compose email
        # mail, recipient_email, csender_email = compose_email(recipient=recipient, sender=sender_email, sender_name=custom_sender_name, subject=email_subject, html=payload)
        mail_data = EmailHandler.compose_email(recipient: recipient, sender: sender_email, sender_name: custom_sender_name, subject: email_subject, html: payload)
        mail = mail_data['msg']
        recipient_email = mail_data['recipient']
        csender_email = mail_data['sender']


        # Login as sender if fail dump sender
        server = false
        while server == false do
            server = EmailHandler.email_login(sender_tuple: sender, mail: mail)
        end

        # Send email
        # print('Sending from %s to %s' % (sender_email, recipient))
        if !EmailHandler.send_email(payload: server, sender_address: sender_email, recipient: recipient_email, server: server)
            # email failed to send
            # Call it again without this sender and with the current limit
            server = EmailHandler.email_login(sender_tuple: sender, mail: server)
        end
    end

    # if server
    #     server.finish
    # end
    return true
end


def main()
    ''' Send email from msg.html to all addresses in army.txt
    with the addresses in senders.txt
    '''

    senders_all = Utils.get_sender_addresses(path: $senders_file_path)
    recipients_all = Utils.get_army_addresses(path: $army_file_path)
    html_content = Utils.get_email_content(path: $email_file_path)

    threads = []

    for th in 0..$threads_total-1
        threc = recipients_all[th..recipients_all.length-1]

        if threc != nil && threc.length > 0

            threads << Thread.new {
                if th == 0
                    sleep 2
                end
                mail_savage(recipients_all, senders_all, html_content, $custom_sender_email, $custom_sender_name, $email_subject, active_limit: nil, active_server: nil)
            }
        end
        # thread.join
        # thread.start()
    end

    threads.each do |t|
        t.join
    end
end

main

所以当我尝试发送邮件时,首先它会多次发送一封邮件,然后其余邮件失败,如下所示 cmd main

然后发生这种情况 error msg

现在我的问题是,为什么在成功发送了几封邮件后,邮件却失败了。我认为脚本中的某处有错误。 有什么帮助吗?

现在我添加了 puts e,我得到了下面的错误代码。请注意,它发送了大约 20 封邮件,其余的都失败了。 error i get now

另外,我怎样才能让代码接受除 365 之外的不同 smtp?

【问题讨论】:

  • 能否请您包含代码 sn-ps 而不是图像?
  • 在您的 self.send_email 方法中,您 rescue Exception =&gt; e 但实际上并没有显示异常是什么。这将是第一件事 - 在 rescue 块中的某处添加 puts e 并查看错误是什么。如果没有这些信息,调试将非常困难。
  • @SaraTibbetts 我编辑了问题以显示代码。有什么帮助吗?
  • @supremebeing7 我无法理解你。你能告诉我你的意思吗?
  • 您正在拯救一个异常并将其存储在变量e 中。在puts 'Email Failed to Send from '+sender_address+' to '+ recipient 行之后,添加puts eputs e.backtrace 行。这将打印带有被救出的错误的变量以及回溯。参考:ruby-doc.org/core-2.2.0/Exception.html

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-4 rubygems


【解决方案1】:

您的错误日志中的相关部分看起来是550 5.1.8 Access denied, bad outbound sender。正如您提到的,您使用 Office 365 作为您的 smtp 提供商,Microsoft 支持网站上有一篇帖子表明这是由于您的 sending address being suspected of sending spam

由于您尝试快速连续发送大量电子邮件,这似乎是您遇到的问题。

如果将同一封电子邮件发送给所有电子邮件,您可以考虑将一封包含所有地址的邮件作为密件抄送发送。否则,您可能需要与您的 Office 365 管理员联系,看看是否有可以调整的设置。您也可以考虑使用交易电子邮件提供商(即 SendGrid、Mailchimp,甚至看起来像是 Microsoft 的交易电子邮件系统 Dynamics Marketing)来处理这些类型的事情,并且通常具有批量邮件操作t 占用你的服务器。

【讨论】:

  • 谢谢。我终于发现问题出在 smtp 提供商上。现在查看脚本,我如何让它接受其他 smtp 提供程序,因为它只适用于 Outlook smtp。
  • 您似乎正在根据 senders.txt 文件中的值配置 smtp 提供程序,因此需要更改这些值。
猜你喜欢
  • 2017-10-30
  • 2021-09-01
  • 1970-01-01
  • 2019-01-11
  • 2015-05-05
  • 1970-01-01
  • 2015-12-21
  • 1970-01-01
相关资源
最近更新 更多