简体   繁体   English

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

[英]Devise not sending emails through ActionMailer

I have read through so many tutorials and answers online and am not finding my fix. 我已经在线阅读了许多教程和答案,但找不到我的解决方法。 I have setup my ActionMailer to send emails through Mailgun's service. 我已经将ActionMailer设置为通过Mailgun的服务发送电子邮件。 I can verify that in production it does send emails through my online contact form without any issues. 我可以验证生产过程中是否确实通过我的在线联系表发送了电子邮件,而没有任何问题。 But, when I try to use one of Devise's restore templates (ie: Forgot Password) the email is not being sent. 但是,当我尝试使用Devise的还原模板之一(即:“忘记密码”)时,电子邮件未发送。

Code

--> config/environments/production.rb ->配置/环境/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"]
}

To try and debug I set raise_deliever_errors to true as seen in the code above. 要尝试调试,如上面的代码所示,我将raise_deliever_errors设置为true。

When I look through the logs I see this (I removed the log timestamps for easier reading): 查看日志时,我看到了这一点(为了方便阅读,我删除了日志时间戳记):

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
):

The key is in the last line where it fails because 401 Unauthorized and Net::SMTPAuthenticationError and basically stating that Mailgun did not like my login credentials. 密钥位于失败的最后一行,因为401 UnauthorizedNet::SMTPAuthenticationError并基本上表明Mailgun不喜欢我的登录凭据。

QUESTION

Here's my question. 这是我的问题。 Where is Devise pulling the information? Devise在哪里获取信息? When I send through the contact form, Mailgun accepts the login credentials that I submit; 当我通过联系表单发送邮件时,Mailgun接受我提交的登录凭据; but when Devise sends, they are not accepted. 但是当Devise发送时,它们不会被接受。 This makes me think that there is a setting somewhere that is not pulling the information from production.rb . 这使我认为某个地方没有从production.rb获取信息。

After 4 days of working on this issue, I was able to come up with a solution. 经过4天的研究,这个问题得以解决。 Not sure if it is the best or most eloquent way of doing it, but just in case anyone else in the future has this same issue, here is what I did. 不知道这是最好的还是最有说服力的方式,但是以防万一将来其他人遇到同样的问题,这就是我所做的。

First, some explanation. 首先,一些解释。 I am not sure why updating the development.rb and production.rb files with my config.action_mailer.smtp_settings didn't work. 我不确定为什么用config.action_mailer.smtp_settings更新development.rbproduction.rb文件不起作用。 By all of the documentation, it seems that Devise should work seamlessly with those settings. 在所有文档中,似乎Devise应该与这些设置无缝地协同工作。 Now, the reason my contact form worked and Devise didn't though is because my contact form was utilizing contact_us_email_mailer.rb which had the code for sending email through Mailgun's API. 现在,我的联系表单有效而Devise却无法正常工作的原因是,因为我的联系表单使用的是contact_us_email_mailer.rb ,其中包含通过Mailgun API发送电子邮件的代码。 (Thank you @kuwantum. Your comment helped me make the connection that I was sending the emails differently.) (谢谢@kuwantum。您的评论帮助我确定了我发送电子邮件的方式有所不同。)

So, my mentality was to figure out how Devise sends it's emails, where it calls the SMTP or API to email, and then enter my information there. 因此,我的想法是弄清楚Devise如何发送电子邮件,在其中调用SMTP或API来发送电子邮件,然后在那输入我的信息。 I went to the Devise Wiki and found a "How To" for setting up a custom mailer file . 我去了Devise Wiki,找到了用于设置自定义邮件文件的“方法” Following these steps, I setup membership_mailer.rb file under app/mailers/ that looked like this: 完成以下步骤后,我在app/mailers/下设置了membership_mailer.rb文件,如下所示:

class MembershipMailer < Devise::Mailer   

  helper :application
  include Devise::Controllers::UrlHelpers

end

And then changed my config/initializers/devise.rb file to point to this new mailer by changing the following line: 然后通过更改以下行,将我的config/initializers/devise.rb文件更改为指向此新邮件程序:

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

I then needed to grab the original Devise mailer code and enter it into this document. 然后,我需要获取原始的Devise邮件程序代码,并将其输入到此文档中。 I got that code here . 我在这里得到了那个代码

devise/mailer.rb devise / 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

Looking at this code, I see the devise_mail being called often, so I needed to find out what that code is. 查看此代码,我发现经常调用devise_mail ,因此我需要找出该代码是什么。 And I got to this page . 我到了这个页面 Searching this site gave me the code that I needed. 搜索该站点给我所需的代码

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

This code then showed a few more function calls that I searched for on the site mentioned above and the code that I needed to understand was the headers_for section. 然后,这段代码显示了我在上述站点上搜索的其他一些函数调用,而我需要理解的代码是headers_for部分。 This is that code: 这是该代码:

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

Running byebug , I was able to call this function and get a hash of responses, and calling each gave me it's value. 运行byebug ,我能够调用此函数并获取响应的哈希,并调用每个函数赋予我它的价值。 So, typing headers_for(action, opts)[:from] gave me the default email that I had setup in the devise.rb file. 因此,键入headers_for(action, opts)[:from]给了我在devise.rb文件中设置的默认电子邮件。 So, that works. 因此,这可行。

Now, for the part that took some trial and error. 现在,对于经过一些反复试验的部分。 I was having difficulty with the SMTP settings for Mailgun but know that the API worked as it was working with my contact form. 我在使用Mailgun的SMTP设置时遇到了困难,但是知道该API可以正常使用,并且可以使用我的联系表单。 So, I needed to get the variables working. 因此,我需要使变量正常工作。 This is the code that worked for my contact form (note that the hidden key was being called from a .env file created with the ' dotenv-rails ' gem and the require statement utilized the ' rest-client ' gem.): 这是适用于我的联系表单的代码(请注意,隐藏密钥是从使用' dotenv- .env创建的.env文件中调用的,而require语句使用了' rest- client'gem 。):

contact_us_email_mailer.rb 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

Now, combining this with the devise_mail function I got this code: 现在,将其与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

I then needed to figure out how to get the email templates created into the email. 然后,我需要弄清楚如何将电子邮件模板创建到电子邮件中。 That is when I came across this StackOverflow answer that pointed me in the right direction and I came up with this code: 那就是我遇到这个StackOverflow答案时 ,它为我指明了正确的方向,并且我想到了以下代码:

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

Adding that to the previous code I got this: 将其添加到之前的代码中,我得到了:

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

The next issue I had to do was change the input of the 'action' from a symbol to a string. 我要做的下一个问题是将“操作”的输入从符号更改为字符串。 For instance :confirmation_instructions became 'confirmation_instructions' . 例如:confirmation_instructions变为'confirmation_instructions'

The last issue was that the system was trying to find all of the mailer templates in a membership_mailer folder instead of the devise/mailers/ folder. 最后一个问题是系统正在尝试在membership_mailer文件夹而不是devise/mailers/文件夹中查找所有邮件模板。 So, I just moved the devise templates into the new folder and that solved that problem. 因此,我将devise模板移到了新文件夹中,就解决了这个问题。

And that did it. 做到了。 The new mailer was being called, sent correctly to the Mailgun API, calling the devise mailer templates from the new folder and sending the emails to the user. 正在调用新邮件,将其正确发送到Mailgun API,从新文件夹中调用devise邮件模板,然后将电子邮件发送给用户。 Hopefully this detailed explanation will help someone in the future. 希望这个详细的解释将对将来的人有所帮助。

Here is the final mailer code: 这是最终的邮递员代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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