← Blog • Published: Tuesday, 24 Oct 2023

ActionMailer attachments in Ruby on Rails

ActionMailer makes it easy to attach files to your emails. In this article, I show you how to attach single or multiple files, set custom encodings and mime_types, and attach images as inline attachments to display in your email body.

If you use ActionMailer to send a lot of emails, at some point, you'll probably want to attach files to them. You might want to send a .pdf invoice to a customer, or attach custom images inline inside a newsletter email.

Fortunately, ActionMailer makes attaching files really easy!

In this article, I'll show you how to send emails with attachments using ActionMailer. We'll cover a few examples, including —

  • attaching a .pdf file to an email,
  • attaching multiple files,
  • adding inline attachments for things like images,
  • and specifying custom encodings for your attachments.

Let's go!

Basic File Attachments

ActionMailer makes it easy to attach files. Each mailer method has access to an attachments hash, which stores attachments and automatically includes them in your emails.

You assign attachments directly to attachments, specifying the file name and content.

To attach a single file (for example, a PDF invoice file) we can write something like this —

# app/mailers/invoice_mailer.rb
#
class InvoiceMailer < ActionMailer::Base
  def send_invoice(invoice)
    # attach a file to our email
    # should reference a binary blob, like from File.read
    attachments['invoice.pdf'] = File.read('path/to/invoice.pdf')

    mail(to: invoice.customer.email, subject: 'Your Invoice')
  end
end

In the code above, we read a PDF file from the disk and assign it to the attachments hash. When we send our email, ActionMailer will attach the file, and call it invoice.pdf (the name we specified).

When the #mail method inside InvoiceMailer#send_invoice is triggered, a multipart email with an attachment is sent. ActionMailer will automatically guess the mime_type for the file and set the encoding, plus handle attaching the file.

For more info, you can read the official Ruby on Rails/ActionMailer docs.

Attaching multiple files

ActionMailer also supports attaching multiple files to your emails, in a very similar way to the above. We just need to assign multiple values to the attachments hash, and then ActionMailer will automatically attach them —

# app/mailers/invoice_mailer.rb
#
class InvoiceMailer < ActionMailer::Base
  def send_invoice(invoice)
    attachments['invoice.pdf'] = File.read('path/to/invoice.pdf')
    attachments['receipt.pdf'] = File.read('path/to/receipt.pdf')
    attachments['refund-policy.pdf'] = File.read('path/to/refund-policy.pdf')

    mail(to: invoice.customer.email, subject: 'Your Invoice')
  end
end

There is no limit to the number of files you can attach, but you will need to keep in mind email attachment size limits. For Gmail, there's a 25MB total file size limit across all attachments.

Setting custom encodings for attachments

By default, ActionMailer will Base64 encode your files. If the default encoding doesn't suit your needs though, you can encode your content differently. Pass the encoded content and encoding to the attachments hash, like so:

encoded_content = SpecialEncode(File.read('/path/to/filename.jpg'))
attachments['filename.jpg'] = {
  mime_type: 'application/gzip',
  encoding: 'SpecialEncoding',
  content: encoded_content
}

By specifying an encoding, ActionMailer will assume that your content is already encoded and won't attempt to Base64 encode it.

Inline Attachments

Rails and ActionMailer also support inline attachments — inline attachments are files to be displayed in the body of your email, typically images or videos.

To create an inline attachment, call #inline on the attachments hash within your mailer —

# welcome_mailer.rb
#
def welcome
  attachments.inline['image.jpg'] = File.read('/path/to/image.jpg')
end

Then in your mailer view, reference attachments as a hash, specify the attachment you want to show, and pass the result to the image_tag method:

# welcome.html.erb
#
<p>Hello there, this is our image</p>
<%= image_tag attachments['image.jpg'].url, alt: 'My Photo', class: 'photos' %>

Conclusion

ActionMailer in Ruby on Rails makes it easy to send emails with attachments, whether it's attaching single or multiple files or inline attachments.

You can also check out the official ActionMailer docs for more information.

If you use ActionMailer a lot to send emails in your Ruby on Rails apps, you'll also probably love RailsNotes UI, a collection of email templates and components for ActionMailer.