General Guidance on Rails Mailers - ruby-on-rails

I am making an event registration tool in Rails and I am having trouble working out the mailing section. I am using Mailgun API and I've got a generic "Thank you for Registering" email working when the user signs up as well as a contact form submission that comes to my email. Part of the requirements for the application is the ability to send promotional emails (separate from Thank you for Registering emails). These promotional emails are more like (One week reminder) type emails.
So these emails need to be able to be created by the admin setting up the event as this is a general purpose tool. So to save the emails the admin creates, I have a mailings object. So the relationship is a bit like this:
Event has many mailers, registrations, etc. (and those belong to the event). They are nested resources because they are specific to an event. Now I need to bridge the gap of how to go from the mailers created by the admin to sending them to Mailgun. The problem is we will have to have the ability to add recipients because they may want to send to people besides the registrants for the event. So I need to go from the mailing#show (which shows a preview of the mailing and will need to be able to add/remove recipients), loop through all of the recipients, and send the message that is in the mailing.message field.
I am so close to finishing this tool except for this mailing which I cannot wrap my head around. I see a lot of examples that create a mailer but I am not sure if that would work for me since the message are unique and it needs to get the message and subject from the mailer object. Any advice or guidance? I am really struggling to get this part done.

I assume you have a User model with an email column
I would setup an extra model i.e.
class PromoMail < ActiveRecord::Base
has_many :users # recpients
validates :body, presence: true
end
Then add a controller, where admins can create these and insert the Mail content in the body field and add recipients.
Then create a new method in your existing mailer to send the mail with the yielded body to one user.
Then add a action to the forementioned controller to send the PromoMail by looping over the associated users and call the ne mailer metod with each.

Couple of steps here, without going into much detail.
1) Make a rake task which looks for any emails which needs to be sent out, and sends them out. You might need to expand your schema to record whether a mail (or mailing or whatever) has been sent already. The rake task itself shouldn't have much code, it should just call a class method in eg User or Mailing or something.
You'll need to think about how the system can decide which emails need to get sent out. I find that flowcharts can be helpful here: it's going to involve iterating over all users, or all mailings, or something, and applying various logical tests to them. You may find that your current schema isn't up to the job, in which case expand it.
2) Schedule this rake task to be run at regular intervals, eg once a day or once a week. Various scheduled task runners are available, eg cron, or if you're on Heroku you'll need to use their Scheduler tool, for example.

Related

Sending newsletters with SendGrid and Rails - What is the best approach?

I have a rails app with sendgrid API setup and I can send transactional emails just fine. Now I want to be able to send newsletters but I'm a bit confused about the flow and how to keep track of which users want to unsubscribe from the newsletter.
The way I was considering doing this is when a use signsup to automatically send a request to the SendGrid API and add them to the contacts list, and if they want to unsubscribe from the newsletter or transactional emails from my app's settings page I can save this info in my app's DB but also send a request to sendgrid's unsubscribe list to change the value there too. Now I can create a newsletter in sendgrid and send it out from there without having to do anything within my app. One caveat to this approach would be if the users clicks the unsubscribe button via the newsletter and the value gets changed in sendgrid but the change won't be reflected in my app - To work around this would it be better to create a cron job that periodically checks sendgrid for any changes and then save them to my DB, or should the unsubscribe page be part of my app, and when they select unsubscribe I save it to my DB and then push the changes to sendgrid? If i do this approach, would I require users to sign in if they want to make these changes?
An alternative approach would be to forego creating any contact lists in sendgrid and just create the email in sendgrid and sent it out using a rake tasks to trigger the sending?
Apologies if this is a very basic question, but this is my first time trying to setup newsletters etc and can't seem to find anything online about the best strategy to take in order to do this - I hope this question makes sense.
Twilio SendGrid developer evangelist here.
This question is a little too opinion based for Stack Overflow, many of the options you describe will work but they rely on whether it's the right decision for your application. But, I will try to give some guidance.
First, however you approach this, I would recommend you set up subuser accounts within SendGrid so that your transactional and newsletter emails come from different subusers. This way unsubscribes from newsletters won't affect transactional emails.
I would use the SendGrid contacts list to send out newsletters. This gives you a lot of power over your contacts without you having to build things yourself. You can segment your lists, create unsubscribe groups (where a user can unsubscribe from a subset of your emails instead of all of them) and send emails from within SendGrid without bothering your Rails app. You can still set up to trigger a newsletter from your app using the API if you want to.
As for maintaining the user's subscription status, I would go with exporting the contact lists and keeping your database up to date that way. The important thing when sending to your contact list is that SendGrid has the source of truth for subscription status and your application can be a bit behind if it needs to be. The SendGrid docs for exporting contacts also say:
Twilio SendGrid recommends exporting your contacts regularly as a backup to avoid issues or lost data.
So this would fulfil that suggestion too.
As for the unsubscribe links, the easiest way is to use the SendGrid unsubscribe form, have SendGrid handle all the unsubscribes, and your exports can keep your database up to date. That also allows you to handle the addition of unsubscribe groups without any more code on your side.
With more work you could create your own unsubscribe form so that your database stays more up to date with the subscription status. Your choice over whether a user should be logged in or not depends on how much friction you want to give the user before they unsubscribe and how much issue you think you might get from users forwarding your emails and having their friends unsubscribe them. That is up to you to decide on though.
Hope this helps a bit!

Create an internal message system with Rails

I have Users that can create DinnerEvent that contain Food. User specify preferred Food using a join table. Would like to create an internal message system that automatically sends out a notice to other Users who "prefer" the Food in the DinnerEvent that was created. Can anyone provide some guidance as to how I can go about approaching this or if there are any good reference resources out there (haven't had much luck searching)? Thought about ActiveMailer but decided I wouldn't want people to get spammed all the time in their email inbox. Would prefer to only use Rails to achieve this.
There's a lot of options here and many use cases to think through. Maybe you can start with something very simple that:
Tracks the last date/time of login for each user
On some page (specific to the logged in user), display all DinnerEvents created since last login that match their Food preferences. Should be simple Active Record to pull this.
Continue to show this list until they dismiss it (record this date/time) or login again
A full blown messaging system will probably require more complex stuff like queues for each user that are subscribed to a master queue. And, possibly an additional backend data store like Redis. I'm purposefully leaving out the details of something like this for now; it's a much bigger topic.

Best way to send registration email (DEVISE)

Devise allows you to customize mailers here.
https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer.
However, I can also make a my own actionmailer like here.
http://railscasts.com/episodes/206-action-mailer-in-rails-3
When a user registers on my site, I would like to send two different emails, one to myself with the registration information and one to the user to thank them for registering.
What is the best way to do this? or is there a method that devise has that would allow me to do this? I was thinking of creating a hook(call back) in the model after a user is created. However, that would mean if I manually create a record, the registration emails would also be sent out. I don't want an email to be sent out if I manually create a user. Any advice?
You could have a callback such as after_create :send_email_to_admin
def send_email_to_admin
# your implementation
end
You would also put a conditional so it doesn't send an email when it's yourself creating the record manually. I do not think Devise offers such an option.
3 workarounds if you don't want to send email to your manually created users.
Create users at first, then add the hook.
Add a special pattern on the email of your manually created users. Say (.*)-very-weird-suffix#weired-email.com. You judge this pattern in the hook.
Add a field in users table to check if the account is created by you. I really don't recommend this unless creating accounts is part of your daily job.

Email Digest for Rail Application

I am working on a rails application where people can follow each other and post comments. Currently I use delayed_jobs for people to get notifications when someone follows them or post a comment. My question is how can I collect all the notifications for one user and create an email digest for notifications and send the email at the end of the day. Putting it in another way, can we collate the delayed_jobs?
Delayed_job won't do this for you, but it's straightforward enough to do yourself.
The simplest thing to do would be to write a rake task that you run once a day, and have the task find all the activity for that user that has occurred in the past day, and then send them an email about that activity.
Right now you are sending an email on a set of actions (following event or comment event).
Instead, if your user is digest-enabled, insert a record into a pending-email-digest table, and then daily process the email digests via a cron job.

Rails - Create separate table or bypass all model validation?

I am currently using wepay with rails. Don't worry this post is nothing about wepay.
So when a customer wants to buy something from my site, he/she will be redirected to wepay.
Then after paying on wepay, wepay will redirect the user to /purchases/received
After X amount of time, Wepay will also do a post call to /purchases/callback to tell me that the payment has been captured (credit card processing is slow)
So my original plan is as follows:
For the Purchase model, have a field, wepay_id and wepay_confirmed.
When the user place an order on wepay, the redirection to /puchases/received will create a purchase instance and save in my db
When the callback is called look up by wepay_id and then set wepay_confirmed to true.
However, as I discovered that the X amount of time could be so fast that /purchases/callback is called before /purchases/received could create the object.
So now I have two options:
Allow /purchases/callback to create an empty Purchase instance with just the id and confirmed = true. As I was doing this, I realized that I no longer can validate my model in the traditional manner. This really bugs me.
Create a separate table called Wepay_Confirmed. Whenever callback is called, create an entry in wepay_confirmed. Map the presence of an (checkout_id) in this table to Purchase.confirmed attribute.
I am thinking of doing 2. How can I do this? Do I have to generate a scaffold for a specific model to map to Wepay_Confirmed?
If you have any other suggestions, please reply
I would try to keep your application the way it is because it does make sense however you should look into returning an error code to wepay and have them submit the request later after the record is created.
Just emailed the developers over at WePay and got this response:
Hi Devin,
We do have automatic IPN retries. Retries happen 5 minutes after the
initial try, if the retry doesn't work, we try 15 minutes later, and
then an hour later. However, right now they are only on empty 404
responses.
The best solution is to actually just ignore the IPN if he does not
have the record in his database. Our IPNs only tell an application to
look up the checkout details with the /checkout call. They do not have
any details of the checkout. Since he should be looking up the
/checkout status anyway when he creates the checkout object on his
end, he doesn't need the IPN to tell him to look up the status in this
case.
If that doesn't work for him he can also email me at api#wepay.com and
we may be able to work out a solution.
Andrew
So it looks like you can modify the flow of you application to ignore the IPN's without a record and check manually or you can respond with a 404 and they will retry at the above intervals.
As I mentioned in my comment, I would personally prefer to create the purchase record upon purchase, then send the user to the WePay site, then handle the return trip and callback as actions to be completed against that original purchase site.
For one, that matches the reality of the transaction more accurately. When a user makes a purchase from your site, it makes sense to me that it's something you should persist at that point.
The two elements of the WePay transaction (the return trip to your site and the charge confirmation callback) would all act on that original purchase record. This will also allow you to see how many people abandon the purchase process when they hit WePay, which could reveal issues in your user experience that might help to maximize conversions.
I created a gem called wepay-rails which handles all of this for you. Under the hood it creates the entry (WepayCheckoutRecord) before sending the payer off to wepay. It has an IPN listener built in that handles the updating of that record. In my personal rails app, I am using state machine on the WepayCheckoutRecord model to track the changes to the state and doing 'things' as the state changes on that record.
I hope that helps.
Adam -
If you take the 2nd approach, you dont need to scaffold it. You can just create a migration and use it inside one of your other 'scaffolds'. Scaffolds are really just a way to get started with a resource. I dont think your intent here is to have a fully-fledged resource. Unless it is then you can use it as a scaffold.

Resources