Our Blog.

Expert thoughts from our software developers and design leaders.

  • Antonio Pagano

    Buffalo+Sendgrid is it possible?

    Sendgrid is one of the most well-known and used email delivering solutions. It has solutions for most (if not all) of the common email sending and delivering issues that we could face as developers. But this post is not about convincing you to use Sendgrid.

    One of the things I love about Buffalo is that it ships with all of the things a product needs for rapid application development and deployment. In this case that is email. Buffalo has a mail package that you can use to integrate sendgrid or any other provider with your app.

    import github.com/buffalo/mail

    Buffalo’s mail package key items are the Sender interface and the Message struct. It also ships with an SMTPSender implementation of the Sender interface which could be used if you have an SMTP server or want to use your gmail/hotmail email to send emails. I do not recommend you to use a single email account for SMTP on production environments but it could be useful when doing very quick iterations and hacks.

    Sender interface

    The Sender interface is a very simple interface which is defined as:

    ...
    type Sender interface {
    	Send(Message) error
    }
    

    What essentially says that anything that has a Send method that receives a mail.Message and returns an error can be considered as a Buffalo email Sender. Simple huh?

    Message struct

    The second part of the equation is the Message struct. This struct is the representation of the email message inside the mail package. It has fields like From, To and Cc which should sound for anyone who has sent or received an email before.

    I will not go into deep details of this one because I just want to give an overview of the email package, but you could go and check it out here.

    Plugin Sendgrid in

    As I mentioned before Buffalo allows developers to implement their own Sender. In order to plug in Sendgrid you will use a Sendgrid implementation for the Sendgrid API.

    github.com/paganotoni/sendgrid-sender
    

    To do so I’m assuming you:

    Assuming that’s all set, lets continue.

    Generating mailers package

    One common pattern/best practice in buffalo is to have your email-sending functions in a package called mailers.

    If you don’t have this folder in your app it means you have not generated it. It doesn’t get generated with the new app. You can generate it by running the following command:

    buffalo g mailer your_first_mailer_name
    

    This will generate:

    • mailers folder
    • mailers.go file
    • your_first_mailer_name.go file (with your first mailer there).

    Lets focus on the mailers/mailers.go file.

    Modifying mailers.go

    mailers.go file is the place where the mailers configuration resides. At the moment I’m writing this (buffalo v0.14.10) after running the command I mentioned before that file looks like this:

    ...
    var smtp mail.Sender
    var r *render.Engine
    
    func init() {
    
    	// Pulling config from the env.
    	port := envy.Get("SMTP_PORT", "1025")
    	host := envy.Get("SMTP_HOST", "localhost")
    	user := envy.Get("SMTP_USER", "")
    	password := envy.Get("SMTP_PASSWORD", "")
    
    	var err error
    	smtp, err = mail.NewSMTPSender(host, port, user, password)
    
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	r = render.New(render.Options{
            HTMLLayout: "layout.html",
    		TemplatesBox: packr.New("app:mailers:templates", "../templates/mail"),
            Helpers: render.Helpers{},
    	})
    }
    

    This is cool if you were going to use the SMTP sender. It has everything you need to use it. However, since we’re going to use the Sendgrid sender we will need to change it to be:

    
    import (
        ... 
        ssender "github.com/paganotoni/sendgrid-sender"
    )
    
    var sender mail.Sender
    var r *render.Engine
    
    func init() {
    	APIKey := envy.Get("SENDGRID_API_KEY", "")
    	sender = ssender.NewSendgridSender(APIKey)
    
        r = render.New(render.Options{
            HTMLLayout: "layout.html",
    		TemplatesBox: packr.New("app:mailers:templates", "../templates/mail"),
            Helpers: render.Helpers{},
    	})
    }
    

    This will require now that you add your Sendgrid API key to your development and production servers as an environment variable SENDGRID_API_KEY. This is so the Sendgrid Mailer is able to communicate with the Sendgrid API in order to send your emails.

    And as long as the same sender.Send method is called from within your mailer functions all will work as with the default SMTPSender. p.e:

    func NotifyForgotPassword(user models.User) error {
    	m := mail.NewMessage()
    	m.Subject = "Your password change request"
    	m.From = "do-not-reply@wawand.co"
    	m.To = []string{}
    
    	err := m.AddBody(r.HTML("password-forgot.html"), render.Data{
            "FullName":     user.FullName(),
            ...
    		"Link":         user.ForgotPasswordLink(),
    		"ReportLink":   user.ReportForgotPasswordLink(),
    	})
    	
    	if err != nil {
    		return err
    	}
    
    	return smtp.Send(m)
    }
    
    

    And that’s all. You can now use sendgrid to send emails for your Buffalo app.

    Wrapping up

    Thank you for reading this article. I hope you have enjoyed this brief description on how to use Sendgrid with your Buffalo app. If you are using Postmark I wrote a Sender for it, you can check it out here.

    If you have questions or comments about this post, you can find me on twitter at @paganotoni. You can also find my company at @wawandco. I would love to hear your opinions on this and other posts.

    Continue Reading