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

时间:2022-10-25 18:14:56

I saw this post but mine is slightly different:

我看过这个帖子但是我的略有不同:

Rails ActionMailer with multiple SMTP servers

Rails ActionMailer具有多个SMTP服务器

I am allowing the users to send mail using their own SMTP credentials so it actually does come from them.

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

But they will be sent from the Rails app, so that means for each user I need to send their emails using their own SMTP server.

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

How can I do that?

我怎样才能做到这一点?

5 个解决方案

#1


3  

Just set the ActionMailer::Base configuration values before each send action.

只需在每个发送操作之前设置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 = ..

#2


56  

Doing what is described in the other answer is not safe; you are setting class variables here, not instanced variables. If your Rails container is forking, you can do this, but now your application is depending on an implementation detail of the container. If you're not forking a new Ruby process, then you can have a race condition here.

做其他答案中描述的内容并不安全;你在这里设置类变量,而不是实例变量。如果您的Rails容器正在分叉,您可以执行此操作,但现在您的应用程序依赖于容器的实现细节。如果你没有分配新的Ruby进程,那么你可以在这里遇到竞争条件。

You should have a model that is extending ActionMailer::Base, and when you call a method, it will return a Mail::Message object. That is your instance object and is where you should change your settings. The settings are also just a hash, so you can inline it.

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

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

Where in the above mail_settings returns some hash with appropriate keys IE

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

{:user_name=>username, :password=>password}

#3


12  

Here is a solution that I came up with based on the previous answers and comments. This uses an ActionMailer interceptor class.

这是我根据之前的答案和评论提出的解决方案。这使用ActionMailer拦截器类。

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

#4


9  

For Rails 3.2.x

对于Rails 3.2.x

You can include AbstractController::Callbacks in your mailer class and the do a "after_filter :set_delivery_options" inside the mailer.

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

The set_delivery_options method would have access to instance variables setup by you in your mailer action and you can access the mail object as "message".

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


3  

in case somebody needs to set delivery method dynamically together with smtp credentials, u can use Mail::Message instance method to set delivery method together with it's variables so my addapted Aditya Sanghi version is:

如果有人需要与smtp凭证一起动态设置传递方法,你可以使用Mail :: Message实例方法设置传递方法和它的变量,所以我的addapted 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

#1


3  

Just set the ActionMailer::Base configuration values before each send action.

只需在每个发送操作之前设置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 = ..

#2


56  

Doing what is described in the other answer is not safe; you are setting class variables here, not instanced variables. If your Rails container is forking, you can do this, but now your application is depending on an implementation detail of the container. If you're not forking a new Ruby process, then you can have a race condition here.

做其他答案中描述的内容并不安全;你在这里设置类变量,而不是实例变量。如果您的Rails容器正在分叉,您可以执行此操作,但现在您的应用程序依赖于容器的实现细节。如果你没有分配新的Ruby进程,那么你可以在这里遇到竞争条件。

You should have a model that is extending ActionMailer::Base, and when you call a method, it will return a Mail::Message object. That is your instance object and is where you should change your settings. The settings are also just a hash, so you can inline it.

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

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

Where in the above mail_settings returns some hash with appropriate keys IE

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

{:user_name=>username, :password=>password}

#3


12  

Here is a solution that I came up with based on the previous answers and comments. This uses an ActionMailer interceptor class.

这是我根据之前的答案和评论提出的解决方案。这使用ActionMailer拦截器类。

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

#4


9  

For Rails 3.2.x

对于Rails 3.2.x

You can include AbstractController::Callbacks in your mailer class and the do a "after_filter :set_delivery_options" inside the mailer.

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

The set_delivery_options method would have access to instance variables setup by you in your mailer action and you can access the mail object as "message".

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


3  

in case somebody needs to set delivery method dynamically together with smtp credentials, u can use Mail::Message instance method to set delivery method together with it's variables so my addapted Aditya Sanghi version is:

如果有人需要与smtp凭证一起动态设置传递方法,你可以使用Mail :: Message实例方法设置传递方法和它的变量,所以我的addapted 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