如何使用 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 的电子邮件的主要内容,如果未能解决你的问题,请参考以下文章
如何在命令中使用 client.on('quildMemberAdd') 事件?
如何使用Sqlserver 2012 Always on技术