[英]Rails ActionMailer with multiple SMTP servers
I have a need to use two different smtp servers in a Rails application. 我需要在Rails应用程序中使用两个不同的smtp服务器。 It appears that the way ActionMailer is constructed, it is not possible to have different smtp_settings for a subclass.
似乎ActionMailer的构造方式,不可能为子类设置不同的smtp_settings。 I could reload the smtp settings for each mailer class whenever a message is being sent, but that messes up the ExceptionNotifier plugin which is outside my control (unless I mess with it too).
每当发送消息时,我都可以为每个邮件程序类重新加载smtp设置,但这会混淆我无法控制的ExceptionNotifier插件(除非我也搞乱它)。 Does anyone have a solution/plugin for something like this?
有没有人有这样的解决方案/插件?
Ideally I would like to have 理想情况下我想拥有
class UserMailer < ActionMailer::Base; end
and then set in environment.rb 然后在environment.rb中设置
ActionMailer::Base.smtp_settings = standard_smtp_settings
UserMailer.smtp_settings = user_smtp_settings
Thus, most of my mailers including ExceptionNotifier would pickup the default settings, but the UserMailer would use a paid relay service. 因此,我的大多数邮件程序(包括ExceptionNotifier)都会提取默认设置,但UserMailer会使用付费中继服务。
Based on the Oreilly article, I came up with the solution I wrote about here: http://transfs.com/devblog/2009/12/03/custom-smtp-settings-for-a-specific-actionmailer-subclass 根据Oreilly的文章,我想出了我在这里写的解决方案: http : //transfs.com/devblog/2009/12/03/custom-smtp-settings-for-a-specific-actionmailer-subclass
Here's the relevant code: 这是相关的代码:
class MailerWithCustomSmtp < ActionMailer::Base
SMTP_SETTINGS = {
:address => "smtp.gmail.com",
:port => 587,
:authentication => :plain,
:user_name => "custom_account@transfs.com",
:password => 'password',
}
def awesome_email(bidder, options={})
with_custom_smtp_settings do
subject 'Awesome Email D00D!'
recipients 'someone@test.com'
from 'custom_reply_to@transfs.com'
body 'Hope this works...'
end
end
# Override the deliver! method so that we can reset our custom smtp server settings
def deliver!(mail = @mail)
out = super
reset_smtp_settings if @_temp_smtp_settings
out
end
private
def with_custom_smtp_settings(&block)
@_temp_smtp_settings = @@smtp_settings
@@smtp_settings = SMTP_SETTINGS
yield
end
def reset_smtp_settings
@@smtp_settings = @_temp_smtp_settings
@_temp_smtp_settings = nil
end
end
class UserMailer < ActionMailer::Base
def welcome_email(user, company)
@user = user
@url = user_url(@user)
delivery_options = { user_name: company.smtp_user,
password: company.smtp_password,
address: company.smtp_host }
mail(to: @user.email,
subject: "Please see the Terms and Conditions attached",
delivery_method_options: delivery_options)
end
end
Rails 4 allows for dynamic delivery options. Rails 4允许动态交付选项。 The above code is straight from the action mailer basics guide, which you can find here: http://guides.rubyonrails.org/v4.0/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options
上面的代码直接来自动作邮件基础知识指南,您可以在此处找到: http : //guides.rubyonrails.org/v4.0/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options
With this, it is possible to have different smtp settings for every email you send, or, like in your use case for different sub classes like UserMailer, OtherMailer etc. 有了这个,您可以为您发送的每封电子邮件设置不同的smtp设置,或者像在Usercase,OtherMailer等不同子类的用例中一样。
Solution for Rails 4.2+: Rails 4.2+的解决方案:
config/secrets.yml : config / secrets.yml :
production:
gmail_smtp:
:authentication: "plain"
:address: "smtp.gmail.com"
:port: 587
:domain: "zzz.com"
:user_name: "zzz@zzz.com"
:password: "zzz"
:enable_starttls_auto: true
mandrill_smtp:
:authentication: "plain"
:address: "smtp.mandrillapp.com"
:port: 587
:domain: "zzz.com"
:user_name: "zzz@zzz.com"
:password: "zzz"
:enable_starttls_auto: true
mailgun_smtp:
:authentication: "plain"
:address: "smtp.mailgun.org"
:port: 587
:domain: "zzz.com"
:user_name: "zzz@zzz.com"
:password: "zzz"
:enable_starttls_auto: true
config/environments/production.rb : config / environments / production.rb :
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = Rails.application.secrets.gmail_smtp
app/mailers/application_mailer.rb : app / mailers / application_mailer.rb :
class ApplicationMailer < ActionMailer::Base
default from: '"ZZZ" <zzz@zzz.com>'
private
def gmail_delivery
mail.delivery_method.settings = Rails.application.secrets.gmail_smtp
end
def mandrill_delivery
mail.delivery_method.settings = Rails.application.secrets.mandrill_smtp
end
def mailgun_delivery
mail.delivery_method.settings = Rails.application.secrets.mailgun_smtp
end
end
app/mailers/user_mailer.rb : app / mailers / user_mailer.rb :
class UserMailer < ApplicationMailer
# after_action :gmail_delivery, only: [:notify_user]
after_action :mandrill_delivery, only: [:newsletter]
after_action :mailgun_delivery, only: [:newsletter2]
def newsletter(user_id); '...' end # this will be sent through mandrill smtp
def newsletter2(user_id); '...' end # this will be sent through mailgun smtp
def notify_user(user_id); '...' end # this will be sent through gmail smtp
end
For anybody approaching this issue with later versions (3+) of Rails, try this 对于任何与Rails的更高版本(3+)接近此问题的人,请尝试这样做
http://guides.rubyonrails.org/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options http://guides.rubyonrails.org/action_mailer_basics.html#sending-emails-with-dynamic-delivery-options
Tried to use jkrall's option with Rails 3.2.1 but for some reason it wouldn't override default configuration, but doing: 试图在Rails 3.2.1中使用jkrall的选项,但由于某种原因它不会覆盖默认配置,但是:
MyMailer.my_email.delivery_method.settings.merge!(SMTP_SETTINGS).deliver
Similar to http://www.scottw.com/multiple-smtp-servers-with-action-mailer , made it work. 与http://www.scottw.com/multiple-smtp-servers-with-action-mailer类似,使其有效。
Rails-2.3.* Rails的2.3。*
# app/models/user_mailer.rb
class UserMailer < ActionMailer::Base
def self.smtp_settings
USER_MAILER_SMTP_SETTINGS
end
def spam(user)
recipients user.mail
from 'spam@example.com'
subject 'Enlarge whatever!'
body :user => user
content_type 'text/html'
end
end
# config/environment.rb
ActionMailer::Base.smtp_settings = standard_smtp_settings
USER_MAILER_SMTP_SETTINGS = user_smtp_settings
# From console or whatever...
UserMailer.deliver_spam(user)
I'm afraid it's not doable natively. 我担心这本身不可行。
But you can trick it a bit by modifying the @@smtp_settings variable in the model. 但是你可以通过修改模型中的@@ smtp_settings变量来欺骗它。
There's an article on Oreilly which explains it pretty well even though they code is not clean at all. 有一篇关于Oreilly的文章很好地解释了它,即使它们的代码根本不干净。 http://broadcast.oreilly.com/2009/03/using-multiple-smtp-accounts-w.html
http://broadcast.oreilly.com/2009/03/using-multiple-smtp-accounts-w.html
Solution for Rails 3.2: Rails 3.2的解决方案:
class SomeMailer < ActionMailer::Base
include AbstractController::Callbacks
after_filter :set_delivery_options
private
def set_delivery_options
settings = {
:address => 'smtp.server',
:port => 587,
:domain => 'your_domain',
:user_name => 'smtp_username',
:password => 'smtp_password',
:authentication => 'PLAIN' # or something
}
message.delivery_method.settings.merge!(settings)
end
end
Solution inspired by How to send emails with multiple, dynamic smtp using Actionmailer/Ruby on Rails 解决方案的灵感来自如何使用Actionmailer / Ruby on Rails发送具有多个动态smtp的电子邮件
When I wanted a quick test in the console (Rails 5) I did the following: 当我想在控制台(Rails 5)中进行快速测试时,我做了以下事情:
settings = { username: "" } # etc
mailer = MyMailer.some_method
mailer.delivery_method.settings.merge!(settings)
mailer.deliver
https://github.com/AnthonyCaliendo/action_mailer_callbacks https://github.com/AnthonyCaliendo/action_mailer_callbacks
I found this plugin helped solve the problem for me pretty easily (as in < 5 mins). 我发现这个插件很容易帮我解决问题(如<5分钟)。 I simply change the @@smtp_settings for a particular mailer in the before_deliver and then change it back to the defaults in the after_deliver.
我只需更改before_deliver中特定邮件程序的@@ smtp_settings,然后将其更改回after_deliver中的默认值。 Using this approach, I only have to add the callbacks to mailers that need @@smtp_settings different than the default.
使用这种方法,我只需要将回调添加到需要不同于默认值的@@ smtp_settings的邮件程序。
class CustomMailer < ActionMailer::Base
before_deliver do |mail|
self.smtp_settings = custom_settings
end
after_deliver do |mail|
self.smtp_settings = default_settings
end
def some_message
subject "blah"
recipients "blah@blah.com"
from "ruby.ninja@ninjaness.com"
body "You can haz Ninja rb skillz!"
attachment some_doc
end
end
Here's another solution, which, while it looks ridiculous, I think is a little bit cleaner and easier to reuse in different AM::Base classes: 这是另一个解决方案,虽然看起来很荒谬,但我认为在不同的AM :: Base类中重用更简洁一些:
module FTTUtilities
module ActionMailer
module ClassMethods
def smtp_settings
dict = YAML.load_file(RAILS_ROOT + "/config/custom_mailers.yml")[self.name.underscore]
@custom_smtp_settings ||= HashWithIndifferentAccess.new(dict)
end
end
module InstanceMethods
def smtp_settings
self.class.smtp_settings
end
end
end
end
example Mailer: 梅勒:
class CustomMailer < ActionMailer::Base
extend FTTUtilites::ActionMailer::ClassMethods
include FTTUtilites::ActionMailer::InstanceMethods
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.