如何使用 Actionmailer/Ruby on Rails 发送具有多个动态 smtp 的电子邮件

Posted

技术标签:

【中文标题】如何使用 Actionmailer/Ruby on Rails 发送具有多个动态 smtp 的电子邮件【英文标题】:How to send emails with multiple, dynamic smtp using Actionmailer/Ruby on Rails 【发布时间】:2011-02-09 09:41:19 【问题描述】:

我看过这篇文章,但我的略有不同:

Rails ActionMailer with multiple SMTP servers

我允许用户使用他们自己的 SMTP 凭据发送邮件,因此邮件确实来自他们。

但它们将从 Rails 应用程序发送,这意味着对于每个用户,我需要使用他们自己的 SMTP 服务器发送他们的电子邮件。

我该怎么做?

【问题讨论】:

请帮助将此 PR 合并到 Rails 中。 (github.com/rails/rails/pull/7397) 这完全符合您的想法。 【参考方案1】:

只需在每个发送操作之前设置 ActionMailer::Base 配置值。

smtp_config = user.smtp_configuration

ActionMailer::Base.username = smtp_config.username
ActionMailer::Base.password = smtp_config.password
ActionMailer::Base.server = ..
ActionMailer::Base.port = ..
ActionMailer::Base.authentication = ..

【讨论】:

我该怎么做? ActionMailer 配置在配置文件中...创建一个名为 smtp_config 的局部变量,然后传递相应的方法? 所以刚刚丢失了我之前的答案,所以再试一次较短的笔记。您只是在这些调用中设置 ActionMailer 类变量。通常它们在配置中定义,但您可以随时更改它们。在您的情况下,您希望在需要调用的每个 ActionMailer 子类的 Deliver_XXX 方法之前设置它们。 同意,您应该将 jcalvert 的答案重新标记为正确 - 所选答案很危险 这很糟糕。阅读@jcalvert 的回答【参考方案2】:

做另一个答案中描述的事情是不安全的;您在这里设置类变量,而不是实例化变量。如果你的 Rails 容器是分叉的,你可以这样做,但现在你的应用程序依赖于容器的实现细节。如果你没有派生一个新的 Ruby 进程,那么你可以在这里有一个竞争条件。

你应该有一个扩展 ActionMailer::Base 的模型,当你调用一个方法时,它会返回一个 Mail::Message 对象。那是您的实例对象,是您应该更改设置的地方。设置也只是一个哈希,所以你可以内联它。

msg = MyMailer.some_message
msg.delivery_method.settings.merge!(@user.mail_settings)
msg.deliver

在上面的 mail_settings 中返回一些带有适当键的哈希 IE

:user_name=>username, :password=>password

【讨论】:

ActionMailer 的拦截器 (delivering_email) 在某些情况下可能有用。 请帮助将此 PR 合并到 Rails 中。 (github.com/rails/rails/pull/7397) 这完全符合 OP 的想法。 @AdityaSanghi 提到的拉取请求已合并到 Rails 4+,但不会在早期版本中修补。 不错的答案@jcalvert 这正是我对批准答案的担忧 如何在扩展的 actionmailer 模型中做到这一点?这样 SMTP 设置就不会存在于 actionmailer 类之外(您的答案是针对这个问题的,但我们不需要传递因用户而异的凭据。)【参考方案3】:

这是我根据之前的答案和 cmets 提出的解决方案。这使用ActionMailer interceptor class。

class UserMailer < ActionMailer::Base
  default from: proc @user.mail_settings[:from_address]       

  class DynamicSettingsInterceptor
     def self.delivering_email(message)
       message.delivery_method.settings.merge!(@user.mail_settings)
     end
   end
   register_interceptor DynamicSettingsInterceptor
end

【讨论】:

这是一个理想的解决方案,在 Rails 3 中运行良好。【参考方案4】:

对于 Rails 3.2.x

您可以在邮件程序类中包含 AbstractController::Callbacks 并在邮件程序中执行“after_filter :set_delivery_options”。

set_delivery_options 方法可以访问您在邮件操作中设置的实例变量,并且您可以将邮件对象作为“消息”访问。

class MyNailer < ActionMailer::Base
  include AbstractController::Callbacks
  after_filter :set_delivery_options

  def nail_it(user)
    @user = user
    mail :subject => "you nailed it"
  end

  private

  def set_delivery_options
    message.delivery_method.settings.merge!(@user.company.smtp_creds)
  end
end

【讨论】:

【参考方案5】:

如果有人需要动态设置传递方式和 smtp 凭据,你可以使用Mail::Message instance method 来设置传递方式及其变量,所以我添加的Aditya Sanghi 版本是:

class MainMailer < ActionMailer::Base
  WHATEVER_CONDITION = true # example only f.e. @ser

  include AbstractController::Callbacks
  after_filter :set_delivery_options

  private
  def set_delivery_options
    settings = 
    :address => 'smtp.mandrillapp.com', # intentionally
    :port => 587, # intentionally
    :domain => 'your_domain', #insetad of localhost.localdomain'
    :user_name => 'smtp_username',
    :password => 'smtp_password',
    :authentication => 'PLAIN' # or smthing else

    if WHATEVER_CONDITION
      message.delivery_method(:smtp, settings)
    end
  end
end

【讨论】:

WHATEVER_CONDITION 是一个类常量,那么,你为什么需要使用它呢? 你不必这样做,我的意思是你可以使用一些条件来决定你是否需要合并(重写)邮件传递方法,我自己没有使用常量在这里,我的其他邮件程序是从 MainMailer 类继承的,如果满足某些条件,我将使用不同的 smtp 配置,这在我的案例中是所有这些的重点。【参考方案6】:

自 Rails 4+ 起,它可以通过 delivery_method_options 参数直接提供凭据:

class UserMailer < ApplicationMailer
  def welcome_email
    @user = params[:user]
    @url  = user_url(@user)
    delivery_options =  user_name: params[:company].smtp_user,
                         password: params[:company].smtp_password,
                         address: params[:company].smtp_host 
    mail(to: @user.email,
         subject: "Please see the Terms and Conditions attached",
         delivery_method_options: delivery_options)
  end
end

见Sending Emails with Dynamic Delivery Options (Rails Guides)

【讨论】:

这应该是公认的答案!我在这里看到的唯一解决方案不是 hack,它实际上记录在官方 Rail 指南中。

以上是关于如何使用 Actionmailer/Ruby on Rails 发送具有多个动态 smtp 的电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

jQuery:如何使用 .on 事件检查多个元素

如何在命令中使用 client.on('quildMemberAdd') 事件?

如何使用Sqlserver 2012 Always on技术

如何使用 String.Format 将布尔类型转换为“ON”“OFF”

如何使用`on()`委派`hover()`功能[重复]

如何在反应中使用socket.on?