设计不通过ActionMailer发送电子邮件

时间:2018-02-23 20:35:23

标签: ruby-on-rails devise actionmailer

我在线阅读了很多教程和答案,但我找不到修复方法。我已经设置了我的ActionMailer来通过Mailgun的服务发送电子邮件。我可以验证在生产中它确实通过我的在线联系表单发送电子邮件而没有任何问题。但是,当我尝试使用Devise的一个恢复模板(即:忘记密码)时,电子邮件不会被发送。

代码

- >配置/环境/ production.rb

# ActionMailer Config
config.action_mailer.perform_caching = false

config.action_mailer.raise_delivery_errors = true

config.action_mailer.default_url_options = { :host => 'thechristianchain.org' }

config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true

config.action_mailer.default :charset => "utf-8"

config.action_mailer.smtp_settings = {
  :authentication => :plain,
  :address => "smtp.mailgun.org",
  :port => '587',
  :domain => "mx.tccf.co",
  :user_name => ENV["MAILGUN_USERNAME"],
  :password => ENV["MAILGUN_PASSWORD"]
}

尝试调试我将raise_deliever_errors设置为true,如上面的代码所示。

当我查看日志时,我看到了这一点(我删除了日志时间戳以便于阅读):

I, [2018-02-23T20:17:28.511441 #4]  INFO -- : [fb02bfdf-a5c3-4918-bae6-5c5d32ef6fba] Sent mail to info@thechristianchain.org (1028.0ms)

D, [2018-02-23T20:17:28.511562 #4] DEBUG -- : [fb02bfdf-a5c3-4918-bae6-5c5d32ef6fba] Date: Fri, 23 Feb 2018 20:17:27 +0000

From: registrations@thechristianchain.org
Reply-To: registrations@thechristianchain.org
To: info@thechristianchain.org
Message-ID: <5a9076d776379_4233fb2465758@2694484e-c3cb-44d0-8ece-832cd70adf2c.mail>
Subject: Reset password instructions
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: 7bit

<p>Hello info@thechristianchain.org!</p>

<p>Someone has requested a link to change your password. You can do this through the link below.</p>

<p><a href="http://thechristianchain.org/password/edit?reset_password_token=1gtx9XHmTzUjf97YhJdG">Change my password</a></p>

<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>

I, [2018-02-23T20:17:28.511950 #4] INFO -- : [fb02bfdf-a5c3-4918-bae6-5c5d32ef6fba] Completed 401 Unauthorized in 1044ms (ActiveRecord: 5.7ms)
F, [2018-02-23T20:17:28.513684 #4] FATAL -- : [fb02bfdf-a5c3-4918-bae6-5c5d32ef6fba]   
F, [2018-02-23T20:17:28.513764 #4] FATAL -- : [fb02bfdf-a5c3-4918-bae6-5c5d32ef6fba] Net::SMTPAuthenticationError (535 5.7.0 Mailgun is not loving your login or password
):

密钥位于失败的最后一行,因为401 UnauthorizedNet::SMTPAuthenticationError并且基本上说明Mailgun不喜欢我的登录凭据。

问题

这是我的问题。 Devise在哪里提取信息?当我通过联系表单发送邮件时,Mailgun会接受我提交的登录凭据;但是当Devise发送时,他们不被接受。这让我觉得某个地方有一个设置没有从production.rb中提取信息。

1 个答案:

答案 0 :(得分:0)

在解决这个问题4天后,我能够找到解决方案。不确定这是否是最好或最有说服力的方式,但是如果将来其他人都有同样的问题,这就是我所做的。

首先,一些解释。我不确定为什么使用development.rb更新production.rbconfig.action_mailer.smtp_settings文件无效。通过所有文档,似乎Devise应该与这些设置无缝协作。现在,我的联系表单工作的原因和Devise没有,因为我的联系表单正在使用contact_us_email_mailer.rb,其中包含通过Mailgun API发送电子邮件的代码。 (谢谢@kuwantum。你的评论帮助我建立了以不同方式发送电子邮件的连接。)

所以,我的心态是弄清楚Devise如何发送它的电子邮件,它将SMTP或API称为电子邮件,然后在那里输入我的信息。我去了Devise Wiki,找到了setting up a custom mailer file的“How To”。按照这些步骤操作,我在membership_mailer.rb下设置app/mailers/文件,如下所示:

class MembershipMailer < Devise::Mailer   

  helper :application
  include Devise::Controllers::UrlHelpers

end

然后通过更改以下行将我的config/initializers/devise.rb文件更改为指向此新邮件:

# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
  config.mailer = 'MembershipMailer'

然后我需要获取原始的Devise邮件代码并将其输入到本文档中。我得到了code here

色器件/ mailer.rb

def confirmation_instructions(record, token, opts={})
  @token = token
  devise_mail(record, :confirmation_instructions, opts)
end

def reset_password_instructions(record, token, opts={})
  @token = token
  devise_mail(record, :reset_password_instructions, opts)
end

def unlock_instructions(record, token, opts={})
  @token = token
  devise_mail(record, :unlock_instructions, opts)
end

def email_changed(record, opts={})
  devise_mail(record, :email_changed, opts)
end

def password_change(record, opts={})
  devise_mail(record, :password_change, opts)
end

看看这段代码,我看到devise_mail经常被调用,所以我需要找出代码是什么。我到了this page。搜索此网站给了我the code我需要的内容。

def devise_mail(record, action, opts = {}, &block)
  initialize_from_record(record)
  mail headers_for(action, opts), &block
end

然后,此代码显示了我在上述网站上搜索的一些函数调用,我需要了解的代码是headers_for部分。这就是代码:

def headers_for(action, opts)
  headers = {
    subject: subject_for(action),
    to: resource.email,
    from: mailer_sender(devise_mapping),
    reply_to: mailer_reply_to(devise_mapping),
    template_path: template_paths,
    template_name: action
  }.merge(opts)

  @email = headers[:to]
  headers
end

运行byebug,我能够调用此函数并获得响应的哈希值,并且调用每个函数给了我它的值。因此,输入headers_for(action, opts)[:from]会向我提供我在devise.rb文件中设置的默认电子邮件。所以,这是有效的。

现在,对于经过一些试验和错误的部分。我在使用Mailgun的SMTP设置时遇到了困难,但是知道API在处理我的联系表单时工作正常。所以,我需要让变量工作。这是适用于我的联系表单的代码(请注意,隐藏密钥是从使用“dotenv-rails”gem创建的.env文件中调用的,require语句使用了“{ {3}}'宝石。):

contact_us_email_mailer.rb

require 'rest-client'

def send_email(from, to, subject, text)
  RestClient.post ENV.fetch("MAILGUN_MX_URL"),
    :from => from,
    :to => to,
    :subject => subject,
    :text => text
end

现在,将它与devise_mail函数结合起来我得到了这段代码:

def mail(record, action, opts = {}, block)
  initialize_from_record(record)

  RestClient.post ENV.fetch("MAILGUN_MX_URL"),
    :from => headers_for(action, opts)[:from],
    :to => headers_for(action, opts)[:to],  
    :subject => headers_for(action, opts)[:subject],
end

然后我需要弄清楚如何将电子邮件模板创建到电子邮件中。那是当我遇到这个rest-client时,我指出了正确的方向,我想出了这个代码:

html_output = render_to_string(:action => action, :layout => false)
:html => html_output.to_str

将它添加到上一个代码我得到了这个:

def mail(record, action, opts = {}, block)
  initialize_from_record(record)
  html_output = render_to_string(:action => action, :layout => false)

  RestClient.post ENV.fetch("MAILGUN_MX_URL"),
    :from => headers_for(action, opts)[:from],
    :to => headers_for(action, opts)[:to],  
    :subject => headers_for(action, opts)[:subject],
    :html => html_output.to_str
end

我必须做的下一个问题是将'action'的输入从符号更改为字符串。例如:confirmation_instructions成为'confirmation_instructions'

最后一个问题是系统试图找到membership_mailer文件夹而不是devise/mailers/文件夹中的所有邮件程序模板。所以,我只是将设计模板移动到新文件夹中,这解决了这个问题。

就是这样做的。正在调用新的邮件程序,正确发送到Mailgun API,从新文件夹调用设计邮件程序模板并将电子邮件发送给用户。希望这个详细的解释将有助于将来的某些人。

以下是最终的邮件代码:

class MembershipMailer < Devise::Mailer   

  helper :application
  include Devise::Controllers::UrlHelpers
  require 'rest-client'

  def mail(record, action, opts = {}, block)
    initialize_from_record(record)
    html_output = render_to_string(:action => action, :layout => false)

    RestClient.post ENV.fetch("MAILGUN_MX_URL"),
      :from => headers_for(action, opts)[:from],
      :to => headers_for(action, opts)[:to],  
      :subject => headers_for(action, opts)[:subject],
      :html => html_output.to_str
  end

  def confirmation_instructions(record, token, opts={})
    @token = token
    mail(record, 'confirmation_instructions', opts)
  end

  def reset_password_instructions(record, token, opts={})
    @token = token
    mail(record, 'reset_password_instructions', opts)
  end

  def unlock_instructions(record, token, opts={})
    @token = token
    mail(record, 'unlock_instructions', opts)
  end

  def email_changed(record, opts={})
    mail(record, 'email_changed', opts)
  end

  def password_change(record, opts={})
    mail(record, 'password_change', opts)
  end
end