ActionMailer::Base::NullMail when trying exception_notification in development - ruby-on-rails

I'd like to add the exception_notification gem to our app, however, this happens when I try to manually trigger a mail:
exception
# => #<ZeroDivisionError: divided by 0>
ExceptionNotifier::Notifier.exception_notification(request.env, exception)
# => #<ActionMailer::Base::NullMail:0x007fa81bc7c610>
ExceptionNotifier::Notifier.background_exception_notification(exception)
# => #<ActionMailer::Base::NullMail:0x007fa81bf58190>
In the above example, the console is at a breakpoint inside rescue_from Exception in the ApplicationController after a deliberate 1/0 in some controller.
I'm using delayed_job as well, but - no surprise - ExceptionNotifier::Notifier.background_exception_notification(exception).deliver does not spool anything.
I've already set config.consider_all_requests_local = false in development, but still exception_notification instantiates NullMail. In other parts of the app, mailers work just fine and use sendmail.
Any ideas what I'm doing wrong here? Thanks for your help!

Likely you are using an old version of the ExceptionNotifier and a newer version of ActiveMailer::Base. Not calling the mail command within the email functionality will result in the ActionMailer::Base::NullMail instance returned rather than a Mail instance.
From documentation:
class Notifier < ActionMailer::Base
default :from => 'no-reply#example.com',
:return_path => 'system#example.com'
def welcome(recipient)
#account = recipient
mail(:to => recipient.email_address_with_name,
:bcc => ["bcc#example.com", "Order Watcher <watcher#example.com>"])
end
end

I had my tests / rspec returning NullMail objects. the solution was simple, my code was:
def my_mail(foo)
mail(
to: to,
from: from,
subject: #sample_item.campaign_market.campaign.translation_for(language_id, 'sample_item_mailer.request_review.subject'),
content_type: "text/html"
)
#sample_item.update_attributes!({feedback_requested: true, review_requested_at: Time.now})
TrackingService::Event.new(#user, #user.market, 'sample_items', "request_review_email #{#sample_item.id}").call()
end
what's not immediately clear from the ruby docs is that you need to return the mail function,not just execute it. If you need to do something after building the mail object make sure you return the mail at the end. like so:
def my_mail(foo)
m = mail(
to: to,
from: from,
subject: #sample_item.campaign_market.campaign.translation_for(language_id, 'sample_item_mailer.request_review.subject'),
content_type: "text/html"
)
#sample_item.update_attributes!({feedback_requested: true, review_requested_at: Time.now})
TrackingService::Event.new(#user, #user.market, 'sample_items', "request_review_email #{#sample_item.id}").call()
return m
end

Related

NoMethodError: undefined method `const_defined?' when referring to class methods

I am building an email sending system into an already fairly complex rails app.
From a controller I'm trying to call a method that builds an email and then delivers it.
In controller:
response_for :create, :update do
estimate = current_object.estimate.reload
flash[:success] = "Tier Save Successful. "
flash[:success] += send_estimate_email if estimate.verify && estimate.tiers.select{|t| !t.verified?}.empty?
flash[:notice] = "This service bundle was changed for a previously verified service bundle. Please re-verify after changes are complete" if current_object.auto_unverified
redirect_to [current_object.estimate]
end
def send_estimate_email
return "" if current_object.estimate.requestor_email.blank? || !current_object.estimate.requestor_notified_at.blank?
begin
estimate = current_object.estimate
host = request.host_with_port
binding.pry
success = EstimateEmailer.deliver_verification_complete(estimate, host)
current_object.estimate.notes.create!(:user_id => User.find(:first, :conditions => {:user_type_id => UserType::ROOT.id}).id, :title => "Verification Complete Email Sent", :body => "TO: #{success.to}\nSUBJECT: #{success.subject}\nBODY: #{success.body}")
rescue Exception => e
logger.warn(e)
success = false
end
if success
current_object.estimate.update_attribute(:requestor_notified_at, Time.now)
current_object.estimate.notes.create!(:title => "Auto-email sent to requestor", :body => "TO: #{success.to}\nSUBJECT: #{success.subject}\nBODY: #{success.body}", :user_id => current_user.id)
return "Automatic estimate email was successfully sent to #{current_object.estimate.requestor_email}"
else
return "However, automatic estimate email could not be sent due to an error"
end
end
I don't think there's anything wrong with the email code itself, but for some reason I get this error on the EstimateEmailer.deliver_verification_complete(estimate, host) call:
NoMethodError: undefined method `const_defined?' for "estimate":String
setting a breakpoint in the controller before the EstimateEmailer call I notice that I get the error whenever I try to refer to other classes. Just calling EstimateEmailer or any other class name returns the same error.
I've run into issues with undefined method const_defined? in the past. I'm guessing the issue isn't specific to emailing, but I haven't the slightest idea where to begin debugging.
def verification_complete(estimate, host)
request_id = estimate.integration_transactions.empty? ? "Internal ID #{estimate.id}" : estimate.integration_transactions.last.source_id
#estimate = estimate
#estimate_url = public_estimate_url(estimate.public_id, :host => host, :protocol => 'https')
mail(
subject: "Ref ##{estimate.project_code} Application Hosting Estimate Available for Review: #{request_id}",
to: [estimate.requestor_email, estimate.project_manager_email].reject{|email| email.blank? }.join(','),
from: SUPPORT_ADDRESS
)
end
You're using make_resourceful which has an incompatibility with current versions of ActiveSupport. I've just lodged a PR that addresses it: https://github.com/hcatlin/make_resourceful/pull/16.
Alternatively, you can point to the remote branch in your Gemfile:
gem 'make_resourceful', github: 'carpodaster/make_resourceful', branch: 'fix/incompatibility-with-active-support-dependencies'
I assume this problem only occurs in your development environment, right? In that case, you should be able to avoid it by setting config.eager_load = true in config/environments/development.rb.

Rails 3.2.14: ActionMailer fails to find template in production only

We have a Rails 3.2.14 app that is misbehaving in production only. Emails fail to send with the following error message:
ActionView::MissingTemplate (Missing template /invoice with {:locale=>[:en], :formats=>[:text], :handlers=>[:erb, :builder]}. Searched in:
* "/var/www/appname/releases/20131003214241/app/views"
):
app/mailers/mailer.rb:42:in `block in invoice'
app/mailers/mailer.rb:41:in `invoice'
app/controllers/admin_controller.rb:410:in `resend_invoice'
The Mailer#invoice method looks like this:
def invoice(order, resent=false, receipt_or_invoice = "Receipt")
#order = order
#freebie = #order.freebie?
#mail = true
#transaction = #order.beanstream_transaction
#user = #order.user
recipient = #order.email_receipt_to || #user.email || "support#example.com"
#receipt_or_invoice = receipt_or_invoice
subject = #freebie ? "Your License" : "Your #{receipt_or_invoice.capitalize} and License Information#{ resent ? " (Resent)" : ""}"
mail = mail(:to => [recipient], :subject => subject)
mail.add_part(Mail::Part.new do
content_type 'multipart/alternative'
# THE ODD BIT vv
mail.parts.reverse!.delete_if {|p| add_part p }
end)
mail.content_type 'multipart/mixed'
mail.header['content-type'].parameters[:boundary] = mail.body.boundary
#order.line_items.each do |li|
aq_data = li.license.aquatic_prime_data
if aq_data.present?
attachments[li.license.aquatic_prime_filename] = {content: aq_data, mime_type: 'application/xml'}
end
end
return mail
end
A couple notes.
This behaves fine in development using Pow. Production is using Apache+Passenger.
Before this, the last change we made to our mailer was in June to add a new method. We've seen no other reports about failure to deliver emails. This makes me think something changed in the ActionMailer or other Rails gem that somehow caused this issue.
The error also happens when Mailer.invoice is called from our store controller or other part of the code, so I think it's localized to the Mailer.
In development, we're using Google SMTP server for sending mail, whereas we're using Postmark in production.
Thanks in advance for any help or insights!
Turns out, if something seems very complicated, you're usually doing it wrong. I changed our Mailer#invoice method to be like this and it worked fine:
def invoice(order, resent=false, receipt_or_invoice = "Receipt")
#order = order
#freebie = #order.freebie?
#mail = true
#transaction = #order.beanstream_transaction
#user = #order.user
recipient = #order.email_receipt_to || #user.email || "support#example.com"
#receipt_or_invoice = receipt_or_invoice
subject = #freebie ? "Your License" : "Your #{receipt_or_invoice.capitalize} and License Information#{ resent ? " (Resent)" : ""}"
#order.line_items.each do |li|
aq_data = li.license.aquatic_prime_data
if aq_data.present?
attachments[li.license.aquatic_prime_filename] = {content: aq_data, mime_type: 'application/xml'}
end
end
mail(:to => [recipient], :subject => subject)
end
The key bit is to do the attachments before the mail method. Then the multipart/alternative stuff works fine and the attachments are handled properly.
We still had a problem with Postmark refusing to deliver our custom file extension attachment, but that's a separate issue. I don't know why all the machinations we were going through were gumming up our view template_path or why the problem wasn't manifesting in development, but there it is…

ActionMailer Observer not working

I defined an ActionMailer Observer and it's not being called. How can I go about troubleshooting this? Rails 3.1.3, Ruby 1.9.2. Alternatively, I want a method called whenever an email is sent form a certain ActionMailer subclass. This is the only clean way I could find to implement this (I could call a method from each mailing method in the ActionMailer subclass, but that's not very DRY). Any other suggestions as to how to accomplish this would be welcome.
config/initializers/mail_observer.rb:
class MailObserver
def self.delivered_email(message)
require 'ruby-debug' ; debugger
user = User.find_by_email(message.to[0])
if user
email_type = caller[1]
UserMailerLogging.create!(user_id: #user.id, email_type: email_type, contents: self.body)
end
end
end
ActionMailer::Base.register_observer(MailObserver)
app/mailers/user_mailer:
class UserMailer < ActionMailer::Base
default from: "no-reply#testing.com"
...
def unfinished_setup(user)
#user = user
mail to: user_email(user), subject: "Testing..."
end
...
end
And, in the Rails Console:
irb(main):001:0> UserMailer.unfinished_setup(User.find(1))
=> #<Mail::Message:70192154395900, Multipart: false, Headers: <From: no-reply#testing.com>, <To: Test User<user#testing.com>>, <Subject: Testing...>, <Mime-Version: 1.0>, <Content-Type: text/plain>>
I believe the observer won't fire until you actually deliver the message. Your code in the rails console is only creating the email, not sending it. Adding .deliver to the end should deliver the message and execute the observer code.

sendmail_setting for hostingrails

Good afternoon,
I'm facing a problem about the way to send email through my application hosted on hostingrails.
In my config/initializers I added a file "setup_mailer" containing this
ActionMailer::Base.delivery_method = :sendmail
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.default_charset = "utf-8"
# Production
if Rails.env.production?
ActionMailer::Base.sendmail_settings = {
:location => '/usr/sbin/sendmail',
:arguments => '-i -t -f support#xxxxx.xxx'
}
end
and my mailer is as below
class Notification < ActionMailer::Base
def subscription_confirmation(user)
setup_email(user)
mail(:to => #recipients, :subject => "blabla")
end
protected
def setup_email(user)
#recipients = user.email
#from = "support#xxxxx.xx"
headers "Reply-to" => "support#xxxxx.xx"
#sent_on = Time.now
#content_type = "text/html"
end
end
It seems to work very fine on my local machine. But in production, emails are not sent properly and I receive this message in my support inbox.
A message that you sent using the -t command line option contained no
addresses that were not also on the command line, and were therefore
suppressed. This left no recipient addresses, and so no delivery could
be attempted.
If you have any idea, the support seems cannot help me, hope some of you'll have ideas or config files from hostingrails to share.
Thank you,
albandiguer
I had exactly the same problem - resolved it by removing the -t from the sendmail_settings.
I haven't looked much further to investigate other implications, but at least it works. But from the man page:
-t Extract recipients from message headers. These are added to any
recipients specified on the command line.
With Postfix versions prior to 2.1, this option requires that no
recipient addresses are specified on the command line.
So maybe just a difference in Postfix versions?
Try calling to_s on user.email or specifying user email as "#{user.email}"

Locale not working when called from a rake task

I have a Rails app (2.3.8) where I send emails using ActionMailer from my Controllers, with no problems.
However, I´ve created a rake task to be called from a Cronjob (in Heroku). When those emails are sent, no locale transformations in my dates are made.
I´ve googled to find any kind of solution, but couldn´t.
Anyone can help me?
Thanks.
Here is the code:
cron.rake:
desc 'This task is called by the Heroku cron add-on'
task :cron => :environment do
puts 'Sending diary...'
hollydays = [6,0] #weekend
unless hollydays.member?(Time.zone.now.wday) #if is NOT a weekend
User.all.each do |user|
user.deliver_task_diary
end
end
puts 'done.'
end
user model method:
def deliver_task_diary
TaskMailer.deliver_task_diary(self)
end
the method in TaskMailer model:
def task_diary(user)
next_five_tasks = user.next_five_tasks
last_five_tasks = user.last_five_tasks
recipients "#{user.name} <#{user.email}>"
from "My site <no_reply#mysite.com>"
subject "Your daily tasks."
sent_on Time.zone.now
body :user => user, :next_five_tasks => next_five_tasks, :last_five_tasks => last_five_tasks
end
part of my email template that doesn´t locale:
<%=l task.estimated_delivery_date, :format => :short %>
Solved.
I don´t know if it´s the best way, but I´ve just declared the locale at the very beging of the email html template:
<% I18n.locale = "pt-BR" %>

Resources