Using Rails view templates with Mailgun HTTP API integration

I’m trying to integrate Mailgun’s HTTP API with my Rails app to send emails, but I’m running into issues when trying to use Rails view templates for the email content.

Here’s my current mailer setup:

class EmailService < ActionMailer::Base

  def deliver_notification
    mail_data = Multimap.new
    mail_data[:from] = "Support Team <no-reply@#{@@app_domain}>"
    mail_data[:to] = "[email protected]"
    mail_data[:subject] = "Important Update"
    mail_data[:html] = File.open("#{Rails.root}/app/views/email_service/deliver_notification.html.erb", 'r').to_s.html_safe
    ## I also attempted this approach
    mail_data[:html] = render(template: "deliver_notification.html.erb")
    
    result = RestClient.post "https://api:#{@@api_key}"\
    "@api.mailgun.net/v3/#{@@app_domain}/messages", mail_data

    parsed_result = JSON.parse(result)
  end

end

When I run this code, I get this error:

NoMethodError: undefined method `each_byte’ for nil:NilClass

What’s the proper way to render Rails view templates when using Mailgun’s direct API? I know there are gems that handle this, but I need the full API functionality.

I’m open to any solution that lets me send emails via the API while using Rails views, even if it doesn’t involve ActionMailer.

The issue stems from trying to render ERB templates outside of the normal Rails request cycle. You need to create a proper view context for the template rendering to work correctly.

I ran into this exact problem when building a custom email service. What worked for me was instantiating an ActionView renderer with the proper lookup context:

lookup_context = ActionView::LookupContext.new(ActionController::Base.view_paths)
renderer = ActionView::Base.new(lookup_context)
html_content = renderer.render(template: 'email_service/deliver_notification')

Then use html_content in your mail_data hash. This approach gives you access to all Rails view helpers and properly processes the ERB syntax. Make sure your template path matches your directory structure in app/views.

I’ve dealt with this exact scenario and found that using ApplicationController’s view context works reliably. Instead of trying to render outside the Rails ecosystem, you can leverage the existing controller infrastructure:

controller = ApplicationController.new
html_body = controller.render_to_string(
  template: 'email_service/deliver_notification',
  layout: false
)
mail_data[:html] = html_body

This method maintains access to all your application helpers, instance variables, and routes while avoiding the context issues that cause the each_byte error. The key is setting layout to false unless you specifically need email layouts. I’ve used this approach in production applications where we needed Mailgun’s advanced features like tagging and analytics that aren’t available through standard ActionMailer integrations.

had similar issue before - the problem is you’re reading the erb file directly without actually rendering it. try using ActionView::Base.new.render(file: 'path/to/template', locals: {}) instead of File.open. this will properly compile the erb into html before sending to mailgun api.