Global before_sending_mail callback in Rails - ruby-on-rails

When a user earns 10 points in my application, he gets an email saying "You just earned 10 points!"
If someone earns 10 points per day over a week, I don't mind sending him an email a day – but if someone earns 50 points in a single day, I don't want to send him 5 emails.
So I'd like a way to intercept each outgoing email before it gets sent, examine it, and determine whether I should send it or not. What's the best way to do this?

I have a similar application, where I have a sent_previous_email_at timestamp field for the customer. I just check:
send_email if send_previous_email_at < DateTime.today - 1.days

I would attach some sort of method to either the User model or the Point model (if you have something like that).
class User
def add_points(count)
# Add points
send_email if criteria_is_met
end
def send_email
# Send email
end
end
Not exactly "global", but instead of calling the mailer directly, just use something like this so you can easily add conditional behavior.

Related

Rails—how to see whether an email was sent in the past week

I'm sending an email to inactive users, saying "please sign in within 7 days or your account will be deactivated".
I have a service that will fetch all inactive users and send the email, but I run this daily, and I only want to email each user once, not every day.
class DeactivateOldEmailsService
def run
to_deactivate = User.havent_signed_in_for_n_days(97)
to_deactivate.each { |user| user.update(active: false) }
to_warn = User.havent_signed_in_for_n_days(90)
to_warn.each do |user|
messages_for_user_per_employer = InactiveEmailsMailer.account_will_expire(user).deliver_later
end
end
end
How can I check whether a user has been sent an email already?
It is very hard to check whether an user has been sent a notice email, if you did not save the time the email was sent in the database. There might be still some data in log file, but any sending job are quickly deleted from queue as soon as that email was sent successfully.
From your piece of source code, I guess you might have something like "last_signed_in" in your users table. You can just do it simple and send emails to users if they haven't signed in for exactly 90 days, something like:
to_warn.each do |user|
if user.last_signed_in === 90.days.from_now
messages_for_user_per_employer = InactiveEmailsMailer.account_will_expire(user).deliver_later
end
end
Or you can create a new column notice_deactivation_email_sent_at in users table to check whether an user has received the notice email or not.
I'm actually facing something very similar:
Send weekly emails to user (who subscribed to changes that occurred since last sent), this Job is run every day and I don't want user to receive more than one email a day.
My plan is to store this information on a dedicated column last_sent_at on table users, and send email only if condition DateTime.current - last_sent_at > 7.days is true.
EDIT: I should have read last sentence of previous answer... Exactly what I just described... Sorry!

Rails 5 - Best way to prevent emails from being sent to unsubscribed users

I am using Rails 5.
I have an Affiliate model, with a boolean attribute email_notifications_on.
I am building a quite robust email drip system for affiliates and can't figure out where the best place is to check if the affiliate has email notifications on before delivering the email.
Most of my emails are being sent from Resque BG jobs, a few others from controllers.
Here is an example of how I am checking the subscribe status from a BG job:
class NewAffiliateLinkEmailer
#queue = :email_queue
def self.perform(aff_id)
affiliate = Affiliate.find(aff_id)
if affiliate.email_notifications_on?
AffiliateMailer.send_links(affiliate).deliver_now
end
end
end
It seems like writing if affiliate.email_notifications_on? in 10+ areas is not the right way to do this, especially if I need another condition to be met in the future. Or is this fine?
I thought maybe some sort of callback in the AffiliteMailer would work, but saw many people advising against business logic in the Mailer.
Any thoughts/advice would be appreciated.
To be honest, I don't think any better way than creating a method in Affiliate model as follows,
def should_send_email?
# all business logic come here
# to start with you will just have following
# email_notifications_on?
# later you can add `&&` or any business logic for more conditions
end
You can use this method instead of the attribute. It is more re-usable and extendable. You will still have to use the method in every call. If you like single liners then you can use lambda.

Spree Confirmation Emails

So, I want to set up my Spree store such that confirmation emails are not sent when we create orders in the back-end, since we get customers who place orders outside of our store website, which we would like entered into our Spree database nonetheless. The best way we can think of to do this (if you have another way, by all means chime in) is to disrupt this bit of code in the orders model (you can find it at /core/app/models/spree/order.rb):
def finalize!
# lock all adjustments (coupon promotions, etc.)
all_adjustments.each{|a| a.close}
# update payment and shipment(s) states, and save
updater.update_payment_state
shipments.each do |shipment|
shipment.update!(self)
shipment.finalize!
end
updater.update_shipment_state
save!
updater.run_hooks
touch :completed_at
if paid? #THIS CONDITIONAL IS THE BIT WE ADDED
deliver_order_confirmation_email unless confirmation_delivered?
end
consider_risk
end
Now it's just a matter of testing this. The only kind of payment that can be tested through the GUI is check, and I need to see if this trips with a credit card payment that's been authorized/not authorized/captured/not captured (since Spree's documentation on what qualifies as a payment_state of 'balance_due', 'pending' or 'paid' is pretttty bad). So I've been trying to use factory girl's stuff to make an order like that, and see whether or not a confirmation email has been sent. The only thing I can find for testing confirmation emails, however, involves sending one out, and also I can't find anything that would help me build a factory for an order that specific. Am I missing something?

Logic for sending emails to particular User in Rails

This is more like a conceptual question because I have the feeling that I am doing this wrong:
I have to send emails to some Users that satisfy some conditions. What I have right now is the following:
1) A task that basically does this:
users = User.includes(:aptitudes).where({:role => ['Boy','boy','kid'], :aptitudes => {:name =>'Good'} })
users.each do |user|
MyMailer.report(user).deliver
end
2) In the report method of MyMailer, I have several things:
def report(user)
#user = user
#value = #user.value
#travels = #user.travels.where(:end_at)
#rewards = #user.rewards
# More logic depending of values of User.
...
end
What happens is that in the Mailer itself sometimes a particular property or attribute of the object #user does not satisfy for the email to be sent. I am wondering where am I supposed to make sure that all the Users that I pass to the Mailers will be sent an email ? Shall I create a new method in the rake to do those checkings? Or how would you do that?
Generally speaking, you can do as you wish as long as the name is revealing enough of the intentions.
If you gave me this MyMailer object to use, without knowing the implementation, I would expect it to send a report when requested and not filter out of its own whim... eventually deal with other problems (fail to send, delays, retries etc.) but when I give it a user I want that user to be emailed.
So, to answer your question, yes I would either filter out all the users before calling the Mailer, or define a method in the Mailer called something like report_only_those_users that will take care of the filtering.
By the way, you can pass a list of emails to ActionMailer (section 2.3.4), without having to loop and send one at a time.

rails 3.1: Where to filter out email addresses that have opted out

Trying to figure out the cleanest way prevent sending email to users who have opted out from receiving them in rails 3.1.
I was thinking about overriding Mail.deliver to check the db and determine if the recipients are unsubscribed or not, then conditionally delivering the email.
That seems like the least intrusive way to go about it, but requires creating the Mail objects that are never going to be sent.
Seems like the most resource conscious way would be to do the check in the controller, thus preventing the Mail objects that are never going to be sent from the burden of existence.
This though seems more intrusive and prone to developers forgetting to make the check when creating new mailers.
Is there a standard practice for this situation?
** edit **
This is for managing a collection of users who have opted out of receiving notifications, rather than something like managing subscriptions to a news letter.
If the attribute that determines whether or not to get email notifications is just a field on a model in the DB, you could create a named scope called something like 'want_email_notifications' to get all the users that have subscribed.
So, if you have a User class, and that class has an attribute called opt_out, then you could do something like:
class User < ActiveRecord::Base
named_scope :want_email_notifications, :conditions => ['opt_out = ?', false]
...
end
Then, to call it, you do User.want_email_notifications, which gives you an array of all User objects that want email notifications.
Then, when you're checking whether or not a given user should receive an email notification, write a condition similar to:
send_email_notification(user_in_question) if User.want_email_notifications.include?(user_in_question)
In this example, send_email_notification is the method where you would call the associated delivery method, which actually sends the email.

Resources