Rails: Delayed Job --> Not picking up 'from' field when sending asynchronous mail - ruby-on-rails

I'm running 2.1.1, Rails 3, and having a heckuva time getting the delayed_job gem working. If I strip out handle_asynchronously on a mailer, everything works fine...but if I put it back in, I get:
undefined method `name' for nil:NilClass (where 'name' comes from #contact.name ...which works fine when handle_asynchronously is disabled).
If I strip out all the #contact template info, I get:
"A sender (Return-Path, Sender or From) required to send a message"?
Is this me doing something wrong or some sorta bug? Relevant code below (my#email.here replaced with legit email address)
class ContactMailer < ActionMailer::Base
default :from => "my#email.here"
def contact_mail(contact)
#contact = contact
mail(:to => ENV['MANAGER_EMAIL'], :subject => 'Delayed Job Test', :from => 'my#email.here', :content_type => 'text/plain')
end
handle_asynchronously :contact_mail, :run_at => Proc.new { 2.seconds.from_now }
end
Any suggestions very appreciated.

Try calling the method with the actual email address:
def contact_mail(contact_email)
mail(:to => ENV['MANAGER_EMAIL'], :subject => 'Delayed Job Test', :from => contact_email, :content_type => 'text/plain')
end
That's the only thing I can think of which might help without seeing your actual code. Your error says you're calling name on a nil object, but I can't see anywhere where you're calling .name...

I had the same problem and solved it by removing this line:
default :from => "my#email.here"
But I don't know why it crashed with this line..

Rails 3 Mailers
Due to how mailers are implemented in Rails 3, we had to do a little work around to get delayed_job to work.
# without delayed_job
Notifier.signup(#user).deliver
# with delayed_job
Notifier.delay.signup(#user)
Remove the .deliver method to make it work. It’s not ideal, but it’s the best we could do for now
https://github.com/collectiveidea/delayed_job#rails-3-mailers

Related

rails 3 upgrade - You're using the old API in a mailer class

I'm trying to upgrade an application from rails 2.3 to 3.0.6
which has the following code in rails 2.3
class MessageSender < ActionMailer::Base
def send_message(subject,to,from,body,respondent = nil, content_type = 'text/plain')
#content_type = content_type
#subject = subject
#recipients = to
#from = from
# #sent_on = Time.now
#body = {:body_text => body}
end
end
In the upgrade process the code is modified as below
class MessageSender < ActionMailer::Base
def send_message(subjet,to,from,body,respondent = nil,content_type='text/plain')
mail(:to => to, :subject => subject, :from => from, :body => body, :content_type => content_type)
end
end
by referring to this famous blog about using ActionMailer in rails 3.0
And finally ran rake rails:upgrade:check(checks for rails 3 incompatible functions) and it shows
Old ActionMailer class API
You're using the old API in a mailer class.
More information: http://lindsaar.net/2010/1/26/new-actionmailer-api
The culprits:
- app/models/message_sender.rb
(i.e) It says I'm still using Old API
Can somebody explain what am I missing here ?
Or is there any other way to eliminate "You're using the old API in a mailer class" bug ?
FYI: the gems are updated and environment is ruby 1.8.7,rails 3.0.6
Try throwing your code away and write it again using ActionMailer guide. The reason can be as Frederick suggested but also your code doesn't look very rails 3 way ;).
The first thing that comes to my mind is how you pass body and content type. Body can be just variable which you will use in view and content type will be set automatically based on what views are defined.
I would write something like:
class MessageSender < ActionMailer::Base
def send_message(subject, to, from, body)
# #sent_on = Time.now
#body = body
mail(:to => to, :subject => subject, :from => from)
end
end
Then to render a view:
# app/views/message_sender/send_message.text.erb
My nice text email.
And my body is <%= #body %>
As you can read in the guide, you can also create html version as app/views/message_sender/send_message.text.erb.
Rails upgrade checks your code by running some regular expressions against it. This isn't foolproof, for example it's trying to guard against the old style way to set the subject:
subject "foo"
But the tests used to check for that will catch any instance of the word subject followed by a space (except when used as a symbol). Since you've got an argument call subject this could easily happen. The same is true of from.

ActionMailer's mail method works on Heroku but not on localhost?

The error seems to be very non-descriptive:
failed with ArgumentError: A sender (Return-Path, Sender or From) required to send a message
I think this is not the real problem since I've tried specifying "from" even though I set a default. Also, the code is identical for localhost and Heroku...
def invite_dealer(auction, name, email, dealer)
return false if dealer.bids.where("auction_id = ?", auction.id).present?
#name = name #used on template
#email = email
#auction = auction #this too
mail(:to => #email, :subject => "New Auction - #{auction.car.name}", :from => "realaddressishereonmymachine#ourdomain.com")
end
The error failed with ArgumentError: A sender (Return-Path, Sender or From) required to send a message can occur if mail method was not invoked from invite_dealer method.
So putting conditional return into invite_dealer method before call to mail method is bad idea.
Adding this line to development.rb seems to have fixed it - strange all the other mail methods were working:
Rails.application.routes.default_url_options[:host]= 'localhost:3000'

Problems sending email from post data using ActionMailer

I'm currently using Rails 3 and working on a contact form. My data is being sent and I can access it from the params hash but I am being thrown strange errors when I try to send it to my ActionMailer class to be used in an email.
It's currently throwing this error.
undefined method `TestName' for #<MessageMailer:0x00000003f43af0>
and says the error is on these lines
app/mailers/message_mailer.rb:8:in `message'
app/controllers/contact_controller.rb:20:in `message'
The strange thing is that 'TestName' is the value I have entered into the contact form for the :name input.
Here is my code from message_mailer.rb and contact_controller.rb
MessageMailer
class MessageMailer < ActionMailer::Base
include ActiveModel::Validations
def message(data)
#data = data
validates_presence_of #data[:name]
validates_presence_of #data[:email]
validates_presence_of #data[:website]
validates_presence_of #data[:message]
mail(:from => "email#domain.com", :to => "email#domain.com", :subject => "New Message From #{data.name}")
end
end
ContactController
class ContactController < ApplicationController
def message
if request.post?
#data = {
:name => params[:name],
:email => params[:email],
:website => params[:website],
:message => params[:message]
}
if MessageMailer.message(#data).deliver
redirect('/contact', :flash => 'Thank you for the message. I will get back to you as soon as possible')
else
redirect('/contact', :flash => 'Oops! Something went wrong. I will look into it. Until it\'s fixed you can email me at email#domain.com')
end
else
redirect('/contact', :flash => 'Please fill out the contact form to get in touch.')
end
end
end
It is saying the errors are on the line validates_presence_of #data[:name] in message_mailer.rb and if MessageMailer.message(#data).deliver in contact_controller.rb
Any help would be great!
UPDATE: Alright, I solved the original error but now it is throwing this error wrong number of arguments (0 for 1) on MessageMailer.message(#data).deliver. I have tried changing #data to params to bypass any issues with the #data variable and it is still giving it.
validates_presence_of (and other validation methods) are designed to be class methods that take a property name to test for. So the way you are using them (which is incorrect inside a method) causes it to evaluate to
validates_presence_of TestName
which really results in it checking for
self.TestName
which is why you get the undefined method error.
Ways to fix it...
Don't use validations like that in mailer. Just manually check for emptiness of those strings using String#empty?
Create a separate object to which the #data values get assigned. Use validates_presence_of declarations (at the class level like ActiveRecord) and test using #validate!
HTH
Please follow http://railscasts.com/episodes/206-action-mailer-in-rails-3 and
http://guides.rubyonrails.org/action_mailer_basics.html .
There you might have made mistake in POST data MessageMailer.message(#data) may be class name & function name problem.
Or may be due to you need to restart server after mail configuration setup.
let me know if it is not solved?

How does one use delayed_job to make an Rails 3.0 ActionMailer run asynchronously? Encountering ArgumentErrors

I'm trying to delay a notification email to be sent to users upon signing up to my app. The emails are sent using an ActionMailer which I call InitMailer. The way I am trying to delay the jobs is using collectiveidea's delayed_job https://github.com/collectiveidea/delayed_job. To do this you can see that i specify handle_asynchronously after defining the method initial_email:
class InitMailer < ActionMailer::Base
default :from => "info#blahblahblah.com"
def initial_email(user)
#user = user
#url = "http://www.blahblahblah.com"
mail(:to => user.email,
:subject => "Welcome to my website!"
)
end
handle_asynchronously :initial_email
end
However, I encounter an argument error in my log file "delayed_job.log":
Class#initial_email failed with ArgumentError: wrong number of arguments (1 for 0) - 5
failed attempts
For your information, the email is sent in a controller using the line:
#user = InitUser.new(params[:init_user])
InitMailer.delay.initial_email(#user)
Additionally, when I set up my code without the delay, the emails were sent out without problem (except for the fact that it slowed down my app waiting for gmail servers)
Where is causing the errors here? How can I get the delayed mail to send properly?
Due to the way that Rails3 implements mailers, there are some unusual workarounds for delayed_jobs. For instance, you have seen that to delay the mailing, you write
ExampleMailer.delay.example(user)
While typically you would have to write handle_asynchronously after the method definition, in the case of mailers this declaration (for some reason) prevents that delayed job from working.
So in this code, drop the declaration entirely:
class InitMailer < ActionMailer::Base
default :from => "info#blahblahblah.com"
def initial_email(user)
#user = user
#url = "http://www.blahblahblah.com"
mail(:to => user.email,
:subject => "Welcome to my website!"
)
end
#No handle_asynchronously needed here
end

Rails 3 - abandon sending mail within ActionMailer action

I'm wondering how I could conditionally abandon sending mail within the action ActionMailer action itself.
class SomeMailer < ActionMailer::Base
...
def some_emails
some_models = Model.where(:a => 1)
if !some_models.blank?
mail(...)
else
# What to add here?
# render :nothing => true doesn't work
end
end
end
Now invoking this through SomeMailer.some_emails.deliver! returns an
ArgumentError: A sender (Return-Path, Sender or From) required to send a message
Set perform_deliveries to false, like so:
emails = get_email_list_somehow
if emails.present?
mail options.merge(:bcc => emails)
else
self.message.perform_deliveries = false
end
This will quietly not try to send and should stop the error from happening.
In Rails 3.2.9 you can finally conditionally call mail(). Here's the related GitHub thread. Now the OP's code can be reworked like this:
class SomeMailer < ActionMailer::Base
...
def some_emails
some_models = Model.where(:a => 1)
unless some_models.blank?
mail(...)
end
end
end
The strange thing is, that with Rails 3.1.rc4 and WEBrick, it works fine on my local WEBrick webserver. But as soon as I push to Heroku cedar stack, their WEBrick throws the
ArgumentError: A sender (Return-Path, Sender or From)
You have to remove the conditional statements as stated in above answer. That fixes it so that it also works on Heroku, not just your local machine
I had this same problem. There is no real way to do it within the ActionMailer action so I did the following in my cron task:
users.each do |user|
begin
UserMailer.event_second_reminder_group_user_email(user).deliver
puts " - sending reminder email to user #{user.email}"
rescue
end
end
puts "Complete!"
Now if an error is thrown, it doesn't break the app!
Instead put your conditions in the place where you are making the call to SomeMailer.some_emails.deliver!

Resources