简体   繁体   English

Rails ActionMailer具有多个SMTP服务器

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM