How to Create, Preview, and Send Email From Your Rails App

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
today in the studio I'll show you how to create preview and send emails from your rails app hey folks my Clark here with the pragmatics studio I recently updated a rails app and was reminded of some of that nifty new features in action mailer so today I'll walk you step-by-step through my workflow for sending emails from a rails app let's jump right into it our application lets users list items for sale we have a number of items here I'm just gonna click on the unicycle and then users can also leave comments about a specific item so we've got three comments about the unicycle here now when a comment is posted we want to send an email notification to the user who listed that item for sale so let's just take it step by step first we need to do a wee bit of configuration so let's just get that out of the way we're gonna be sending emails from the development environment so I'm in the config environment development RB file where we can configure our development environment I'll show you how to set this up for production a bit later so the first thing I like to do inside of here is change this line here about rays delivery errors it's by default set to false I like to set that to true by default rails will silently ignore any errors related to sending email which isn't very helpful setting this to true will raise an exception if there's trouble sending email next we need to arrange things so that our emails are delivered out into the world by an SMTP server we'll use Gmail since most folks already have a Google account and I'm just gonna paste some configuration in at the bottom of this file inside of this block here give a little bit of space and I've already got this prepared I'm just gonna paste it in and we'll walk through it now don't sweat the details here here are the important parts first we set up the delivery method to be SMTP that's the protocol for sending email then we have some SMTP settings inside of a hash here we've got the address that's going to be the SMTP server we're using in this case it's Gmail and also the port in this case 587 which is a pretty standard port then you set your domain in this case I'm just gonna leave it at example.com you're gonna change this to whatever your domain name is most of the time you're going to use plain authentication don't worry about this is a pretty standard setting and then we have our username and our password so we can authenticate with our SMTP server now it's a best practice to access credentials such as username and password via environment variables as we've done here to get ahold of environment variables in Rubi we use this e and V constant and then we give it the key for the environment variable that we're interested in in this case I've got an environment variable called gmail underscore username and this will access that environment variable and return the actual value otherwise if you hard code your secret credentials in this file then they're no longer a secret anyone who has access to your code for example on a public github repo can plainly see your username and password environment variables also work great for video training the takeaway here is you never want to expose sensitive information in your source code finally down here at the bottom we need to set this host option which is used to properly generate absolute URLs within our email and in development mode I've just set this to localhost colon 3000 so that's the address that's going to be in the URLs that show up inside of our emails after saving this file away we must restart the rail server for these changes to get picked up the next step is we need to create a new mailer to render and send the email now rails includes a generator to make it easy to create new mailers over here on a terminal I'll just use rails G and then I'll just type in mailer and see what options we get we scroll back up to the top of that the mailer takes the name of the mailer this is going to be a class that it generates and it also takes an optional list of what it calls methods here these are actually the names of the emails and the names of the emails will correspond to method names ok so we can generate our mailer rails G mailer the name of our mailer is gonna be called comment mailer because it's related to sending mails about comments and then the name of the email is going to just be called new underscore comment if you had other emails you just continue to list the names of those emails here but we just have one email so I'm using new comment and you can organize and structure these however you want and we just hit return and it generates all the files we need which we'll look at in turn starting with the files that generate it in this app slash and mailers directory back over in our editor I'll go into app mailers and we see that it generated two files application mailer Darby and comment mailer Darby this application mailer is the base class that all other mailers are going to inherit from we notice that it inherits from action mailer colon colon base and then the first thing it does is it calls this default method and passes in some options any of these options will be applied to all of our emails by default because it's defined up here in this base class the from option is the email address you want to use as the sender of the email it's the address it's being sent from so for example you might change this to something like support at example.com or whatever your domain is then on the second line it sets up this layout we'll return back to this a little bit later it also generated this comment mailer notice that the comic mailer inherits from the application mailer which we were just in now these mailer classes work similarly to rails controllers they inherit from a common base class in this case application mailer they also have methods inside of them notice that this method corresponds to the name that we gave at the command line new comment and those methods are similar to control our actions but instead of generating an HTML response mailer method to generate an email so this new common method is going to generate the email we want we also see that this stubbed-out method includes this @ greeting instance variable and instance variables defined inside of mailer methods are accessible in view templates just like you would expect with a controller action and the last line of these mailer methods must call this mail method to actually create a mail message and return it now you notice we can also pass in options to this method in this case we have the option to this is the person we want to send the email to and to create that email the mail method is gonna render some email templates now the generator went ahead and created two email templates for us to render that mail message and those templates are over in app views the name of our mailer is comment mailer so there's a directory there and then we have two templates notice that the name of the file includes the name of the email it's new underscore comment and then we have new underscore comment HTML DRB that generates an HTML email and new comment text a RB that generates a plain text email if we look in the HTML template what we see it looks just like any other view template we've got some static text and then we can generate dynamic text using ER B for example here they're outputting the value of the @ greeting instance variable because that instance variable is defined in the new comment method we have access to it here and the plain text template does pretty much the same thing it just outputs the email in plain text uses the instance variable again it's a good practice to send both plain text and HTML emails and let the email client decide which one to display and action mailer does all that heavy lifting for us because we have two view templates here with the same name but different content types embedded in their file names both templates will get rendered and sent out in one multi-part email since we're already here in the plain text template let's go ahead and change it so that it generates an email content we want I generally like to start by defining what the email will look like and then we'll backfill and set everything up so I'll just delete what's in here now and we want the email content to be a new comment was posted for your and we want to insert the item name right here to do that we're going to need an instance variable that references that item I'll create that in just a second but I'll just go ahead and set it up now we'll have an add item instance variable and then we can access its access or name to get its name and then we'll put the actual comment body down here so we'll use ARB again and we're gonna need the comment that got created to do that and we'll set that up in an instance variable called comment and then we'll reference its body then it would be handy if we generated a link back to the items page so right here I'll just put to reply to this comment please visit the item page app and use of ARB down here again but we want the URL that references that item page well we've got routes set up so we can use a named route helper method item underscore URL passing it the item instance variable will generate the URL back to that item show page now it's important here to use the underscore URL variant of these named route helpers which generates an absolute URL rather than using underscore path which will just generate a relative URL and the email client needs a full URL to get back to our application save that away so that takes care of the plain text email for the HTML email I'll go into that template and I'm just gonna paste this in it's pretty much the same thing as the plain text email except that we're using HTML tags in here to give this a little bit more structure notice the comment bodies and a block quote we use paragraphs for example and then down here when we're generating the link to the item show page we can actually use to link to helper so just like any other view template we can use helpers inside of our mail templates now both of these templates require an @ item and an @ comment instance variable so we need to go set those back up in the mail method that's over in the comment mailer that we looked at before down inside of the new comment method here I'm going to remove greeting and we know we're gonna need an @ comment instance variable I'll assign that in just a second we also need an @ item instance variable the item is going to be the item that's associated with that comment because the comment was posted for a specific item and we've got a relationship in the database set up so that we can get ahold of that item but where is this comment going to come from well unlike a controller action a mailer method doesn't have access to request parameters so we're not going to get it from the URL instead we're just going to pass it into this method this is gonna be a argument to that method comment and then we'll assign it that way next we need to fix up this two option who do we want to send the email to well we want to send it to the person who listed this item for sale and to do that we take our item we can get the user there's a relationship in the database between an item and the user and get that user's email we also want to set up a subject for this email now you notice the comments up above if you want to support multiple languages you can put the subject inside of an internationalization file for right now I'm just gonna set the subject directly down here we just give it the subject option and we're gonna say new comment for I'm just going to stick this on another line so we've got enough space new comment for I'm going to interpolate the items name the mail me if that takes a number of other options and I'll link to the documentation for that in the notes we don't need to specify who the email is coming from when calling this method here because remember back up in our base class application mailer we have this default and it's setting up the default from option that'll be applied to all of the mailers that we have set up here so we've set it up in one spot all the emails are gonna come from that sender our mailer and our templates are good to go but before actually sending the email I like to preview those plain text and HTML templates just to make sure they look right now in the old days you know like a couple of years ago you would install a gem to actually preview the emails but nowadays it's all built into rails so let's give that a try when we ran the generator the preview file was generated down in this test directory under the mailers directory and it generated a stub test file for us but if you go up above and you open up this previews subdirectory you'll notice that it generated this file comment mailer preview dot RB and inside of here we have a class whose sole responsibility is just to let us preview this email it has a method called new underscore comment but that's not the same as the new underscore comment method that we have up in our mailer this is basically just a wrapper around calling comment mailer dot new comment where our actual mailer method lives there's something a little bit unintuitive about this though notice it's using the class comment mailer and is calling the method on that class so it's calling new comment as if it's a class method but if you look back up on our mailer we actually define this method new comment as an instance method now don't let this throw you rails uses a sleight of hand here what it actually does is it instantiate a new instance of this class and then it calls the instance method new comment on there now the way we have this set up we need to pass a comment into this a new comment method so we need a comment there so how are we going to do that well interestingly to note is that although these preview files live under the test directory by default when you preview an email it's actually running inside of the development environment so we can grab a comment from our development database I'm just gonna grab the last comment then we pass it into this method and it's going to return a new mail message so how do we preview the email well rails actually exposes the previews as URLs if we go up to the top of the file here it says preview all emails at and I'll just copy this address back over in the browser I paste it in that address and we see that we have our comment mailer and then we have a link to the new comment email if you have other emails inside of that class you'll just see a list of links we'll go ahead and click on this you notice it's showing us our HTML email which looks pretty good a new comment was posted for your unicycle which is a link we've got the comment body right there and then we've got the item page link so a person could get back to that item page you can also go look at the plain text email up here that looks pretty good too it just has the URL as plain text and we got the plain text version so that's pretty nifty and you know now that I see these I realize it would be really nice to add a standard signature to the bottom of all the emails you know maybe your standard company signature now one way to do that would be to add the text to the bottom of our actual mail templates there's our HTML template we could add the signature right down here or our plain text template we'd have to add it down there but then if we came up with new mail methods we'd have to remember to add the signature to those templates as well so there's a better way just like controller views can have layouts mailer views can also have layouts and if we look back up in our application mailer base class here we come back to this line layout mailer and since it's defined in this base class it's going to apply to all the mailers or subclasses although you can override it on a per email basis if you like the layouts live down in the app views layouts there's the rest of the layouts of our application but we also have two new layouts we have mailer dot HTML GRB and also mailer dot text ER be those correspond to our HTML or our plain text emails so in the plain text version here we see that as calling yield just as with controller views calling yield is going to render the view in this case it's going to be the mail content inside of this layup but then we can do anything before or after this or basically around that yield so this is great it means we can set up our signature I want to keep my signature really simple it's just gonna be thanks and in the HTML version I'll just go down inside of the body but after the yield and use a paragraph just like that now if we say both those away go back and reload our previews it defaults to the HTML email and you see we have the signature there if we look at the plain text version well we've got our thanks signature down there as well so now any emails we generate have a consistent signature I really love the fact that we can now preview emails using the same a rapid feedback loop as any other view template in rails everything looks good so now we're ready to actually send an email out into the world now just to make sure that everything is configured properly I like to hop into a rails console and just fire off one email from there and to do that we're just gonna use the same two lines of code that we use in the preview file first we're going to get a comment from our development database it's gonna be the last comment and then we're gonna use our comment mailer and we're gonna call that new comment method and pass in the comment again this feels odd that we're calling it as a class method when we know it's defined as an instance method but just go with it and remember that that new comment method calls the mail method at the end which creates a new mail object and returns it from that method so I'm actually gonna assign that returned object to a variable I'll just call it mail over here hey return and you notice we get back this mail message object so the new comment method created this object and returned it but it doesn't actually send the message at this time if we look inside of this object we've got this content type multi-part alternative this tells the email client that the email contains multiple alternative representations of the same email body and then the client can choose to display whichever format it prefers now action mail are new to include two parts because we have a two email templates remember we've got a plain text template and an HTML template and we can see up here that actually rendered both of those to generate this one multi-part email that's a really good example of the power of conventions so now that we have the mail object we can actually deliver that mail we'll take the mail object and we just do that by calling deliver underscore now and that actually send out the email if I scroll back up you see the result of rendering those two templates it filled in all of our dynamic content for us and sent that out and we're left with our mail message now more conventionally you might do this in just one step so let's do this again a little bit differently well grab a different comment this will be the first comment we'll just do this in one step T that would be comment mailer dot new comment pass that comment in and then we know that that returned male object so we just turn around and called deliver underscore now on it now when we use deliver now it's a synchronous call we have to wait until the email is actually sent alternatively you can use deliver underscore later and that will queue up the email to be sent in the background using active job instead of delivering it immediately we don't have a queuing system configured so we'll save that for another time so we sent two emails so we should have two emails in our inbox I actually set things up so that the email associated with the user who owned that item is a test account in my gmail account here's that gmail account on my inbox we have two emails the first one was the first comment I sent which was did you lose the other wheel if we look at the other one so the most recent comment how many wheels does it have so our email actually got delivered out through the Gmail SMTP server so with the mail or complete the final step is to hook it into our app we want to send the email whenever a comment is posted and that happens over here in the create action of the comments controller it saves the comment away right here and then right after that we want to send out that email and I actually copied the line we just used in the console because it's basically the same thing we want here we call the comment mailer class the new comment method passing in a comment except this time we don't have a comment variable we have to use the add comment instance variable that's the comment that just got created and then we go ahead and deliver it save that away and give it a try in the browser back over here on the unicycles show page we'll just add the comment where are the handlebars post that comment all right the comment was created so we should have an email in our inbox back over my gmail account we've got a new mail message and it says where are the Hamill bar so that got delivered okay so we have everything configured to send emails in the development environment but what about when you go into production well let me show you how to set up some production settings for sending emails as a starting point we'll just go back over to our config environment development RB file where we have the development settings set up and just snag all this code where we set up the SMTP server and configuring that host option we'll just copy that and then production level settings go into production dot RB so go down to the bottom of that file give ourselves a little space there I'm just paste those in so what needs to change here well we're always gonna be sending in SMTP as the protocol in terms of the SMTP settings in the development mode we used Gmail now Gmail limits the number of emails that you can send so it's pretty good for low volume transactional emails but in production I'd recommend using another smtp relay service such as mailgun or syn grid or mandrel I'll include some links to these services in the notes they can handle larger volumes they keep your emails from being filtered as spam and can also just track the email deliveries most of them have free plans that allow a reasonable number of emails per month as well so you're just gonna change the address from smtp.gmail.com to whatever address your service is the port is probably going to stay the same your domain is probably gonna stay the same and then you have to change your username and your password depending on which service you're using again I would highly recommend you store those in environment variables in terms of this host option down here we do need to change this this isn't going to be localhost because we want this to be our live production server so in our case it would probably be something like pragmatic studio comm that way the URLs they get generated in the emails have the actual domain name to get linked back into your application but that's pretty much all the changes you're gonna need to make to send emails inside a production environment that wraps up this session hopefully this helps you get started sending emails and rails or upgrade your app to take advantage of some of the new features as always if you found this helpful please leave a comment below we'll see you next time
Info
Channel: The Pragmatic Studio
Views: 21,428
Rating: undefined out of 5
Keywords: Ruby On Rails (Software)
Id: 9eFXEzOPRNs
Channel Id: undefined
Length: 21min 53sec (1313 seconds)
Published: Mon Jul 20 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.