Rails 3 mail to users - ruby-on-rails

I want send newsletter to all registered users, but only the last user (in database) receive the mail.
def letter(nletter)
#nletter = nletter
#users=Newsletter.all
#users.each do |users|
mail(:to => users.email, :subject => #nletter.subject)
end
end
Whats wrong?

If the code you showed us is in your Mailer class, it's because the mail method just sets various attributes on a Mail object. When you loop through all your users and call mail for each one, you're just resetting the subject and (more importantly) the recipient on a single Mail object. So when the function finishes and the Mail is sent out, the current recipient is the last user you set it to - the last user in your database.
You can get around this in two different ways. If it's a generic e-mail (everybody gets the same exact message), you can just pass an array of e-mail addresses as :to:
Note: As Josh points out in the comments, you'll pretty much always want to use :bcc instead of :to, so you don't end up broadcasting your entire mailing list.
def letter(nletter)
#nletter = nletter
#users=Newsletter.all
mail(:to => #users.map(&:email), :subject => #nletter.subject)
end
But if each user gets a custom e-mail ("Hi, #{username}!" or somesuch), you'll have to create a new Mail object for each user. You can do this by calling Mailer.deliver_letter(nletter, user) for each user:
# Somewhere outside of your Mailer:
nletter = "...whatever..."
Newsletter.all.each do |user|
Mailer.deliver_letter(nletter, user)
end
# And your mailer function would look like:
def letter(nletter, user)
#nletter = nletter
mail(:to => user.email, :subject => #nletter.subject)
end
Hope this helps!

Related

ActionMailer Observer: pass extra attributes possible?

I have an ActionMailer Observer that gets triggered on each email and writes some information to a log database table to keep track of who sends emails. I want to add some metadata to this like logged in user, type of email, etc.
class MailObserver
def self.delivered_email(message)
if message.header[:client_id]
EmailLog.create!(:client_id => message.header[:client_id].to_s,
:to => message.to ? message.to.join(',') : nil,
:cc => message.cc ? message.cc.join(',') : nil,
:bcc => message.bcc ? message.bcc.join(',') : nil,
:subject => message.subject.to_s,
:content => message.multipart? ? message.text_part.body.decoded : message.body.decoded,
:reference_type => message.header[:reference_type].to_s,
:reference => message.header[:reference].to_s,
:user_id => message.header[:user_id].to_s)
end
end
end
ActionMailer::Base.register_observer(MailObserver)
All this information is available the moment the mail is created.
I currently pass this data via the message.header, but then the values show up in the actual email that is delivered
Is there a better way to pass information from the ActionMailers to the Observers while preventing this data from actually being sent?
Looking through the mail gem, there isn't a lot you can do with meta data on the Mail object besides the headers.
One approach I considered was persisting the message_id along with user details, etc and then retrieving it again in the observer and perform logging after that.
Another I was toying with was to set the message id myself and load it with the user id, etc but that was much the same as setting headers.
Possibly, you could set the header then unset it again in an interceptor.
You can consider creating new key-value pair inside mail method in the specific mailer class itself.
Example:
class UserMailer
.....
mail(to: email, subject: 'Your subject', user_id: user.id, client_id: client.id)
end
I tried this and it worked. But it appends extra key-values to the response header.
Have you considered using a callback on the mailer itself?
class MyMailer < ApplicationMailer
after_action :log_email!
...
private
def log_email!
EmailLog.create! # should be able to access instance variables from your mailer method here to reference what you need
end
end
Hope that helps!

Altering an email address but not the associated name in a Ruby on Rails Mail interceptor

Background: in a Rails 3.2 app, I have an ActionMailer purchase confirmation email that is manipulated in a "stage" environment so that email destined for addresses associated with payment processor sandbox accounts will actually be sent to the email addresses of the people who manage the sandbox accounts. This is currently done inside the mailer class:
# app/mailers/purchase_mailer.rb
class PurchaseMailer < ActionMailer::Base
default :from => "\"#{SiteConfig.name}\" <#{SiteConfig.support_email}>"
def purchase_notification(purchase)
#purchase = purchase
mail :to => "\"#{purchase.customer_name}\" <#{address_filter(purchase.customer_email)}>",
:subject => "[#{SiteConfig.name}] Purchase Confirmation"
end
private
def address_filter(email_address)
# Check for and remove sandbox identifiers
if Rails.env.stage?
email_address.sub(/_\d+_p(er|re)#/, '#')
else
email_address
end
end
end
But, hey, that looks like a great use case for an interceptor, no? So I pulled out the address_filter method above and added this to the Rails app.
# config/initializers/mail.rb
Mail.register_interceptor(StageMailInterceptor) if Rails.env.stage?
# lib/stage_mail_interceptor.rb
class StageMailInterceptor
def self.delivering_email(message)
receivers = []
message.to.each do |to|
receivers << to.sub(/_\d+_p(er|re)#/, '#')
end
message.to = receivers
end
end
At first glance, this appears to work great. In the stage environment, the email is intercepted and the "to" address becomes the email address I want the email to go to. The person managing the sandbox account used to make the purchase receives the email. Perfect... except the name of the sandbox account is gone. What once was "Joe Example" <joe_1338142567_per#example.com> changed to "Joe Example" <joe#example.com> is now changed to joe#example.com
...the name is now gone.
Looking at the Mail message interface, I see that message.to= can be set with a name, but calling message.to gets me an array of just email addresses without names, whether the name was provided or not.
Question: what is the correct way to alter an email address without altering the name associated with the email address in a mail interceptor?
This doesn't seem like it's the "right" way to do this, but grabbing the "To" header of the message, doing the replacement, and setting with message.to= allows me to preserve the names while altering the email address. So my interceptor became:
# lib/stage_mail_interceptor.rb
class StageMailInterceptor
def self.delivering_email(message)
message.to = message.header["To"].to_s.gsub(/_\d+_p(er|re)#/, '#')
end
end

Rails 3: Contact form to send messages from User Profiles

I worked through some basic tutorials on Rails 3. The goal is a community-website on abilities and activities. I am using Devise for authentication. The creation of user profiles with avatars worked well (thanks to paperclip).
As a next step, I want to enable registered users to send an e-mail to a user from his (or her) profile page. I found a great tutorial on creating a contact form using Google Apps:
http://matharvard.ca/posts/2011/aug/22/contact-form-in-rails-3/
The mailer class in this tutorial looks like:
class NotificationsMailer < ActionMailer::Base
default :from => "noreply#youdomain.dev"
default :to => "you#youremail.dev"
def new_message(message)
#message = message
mail(:subject => "[YourWebsite.tld] #{message.subject}")
end
end
My question: What is the best way to replace you#youremail.dev with the receivers E-Mail-Address? (from the User-Model)
Thanks in advance!
You can modify the new_message to accept the user (or list of users) to whom you want to send the email. Or an array of email addresses if you want to. Then pass the receiver's email address to the mail method as the :to option.
def new_message(receiver, message)
#message = message
mail(:subject => "[YourWebsite.tld] #{message.subject}",
:to => receiver.email_address) # or something similar
end
Then you can invoke your mailer like this
NotificationEmail.new_message(a_user, a_message).deliver
To read the API see here or here (I prefer APIdock).
Also a more comprehensive guide on ActionMailer is available here. If you are new to Rails, you can find more guides here.

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

How to send 'Mark as Important' mail using rails

I need your views as i don't know is it possible or not.
I want some emails send by my application should 'Mark as Important' so that when end user receive this mail in there Evolution/Outlook they should know the importance of email.
Currently when i marked any email using evolution as 'Mark as Important' it changes the colour of mail subject and other fields to red.
Both other answers are correct, but the thing is, Outlook uses a non-standard header for signaling importance. It's called X-Priority, so you have to include it in your outgoing mail. You can also include "X-MSMail-Priority: High" for older Outlooks.
def notification
mail({
:to => 'email#example.com',
:subject => 'My subject',
:from => 'me#somewhere.com',
'Importance' => 'high',
'X-Priority' => '1'}) do |format|
format.text
format.html
end
end
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>"],
:subject => "No way!",
:importance => "High") # <======
end
end
The MIME RFC lists importance as a header that can be sent with MIME email. The values that can be used are high, normal or low. To send an email with an adjusted importance, use an API that allows you to either set the importance via an API method, or one that allows you to set individual headers (such as TMail).
I don't know Ruby, so I can't give you an example, but hopefully this points you in the right direction.

Resources