When you generate a URL in a mailer view, ActionMailer
will raise an error unless you previously
configured it which hostname to use
Show archive.org snapshot
.
There are two options to set the default_url_options
of ActionMailer:
- Hardcoded solution (preferred solution when using Rails with ActiveJob/Sidekiq or Cronjobs)
- Dynamic solution
1. Hardcoded solution
When you are sending mails from outside the request cycle, e.g. ActiveJob/Sidekiq or Cronjobs, you need to configure the default_url_options
in your Rails configuration.
# config/application.rb as fallback/default
Rails.application.default_url_options = { host: 'localhost', port: 3000, protocol: 'http://' }
Rails.application.configure do
# ...
end
# config/environments/staging.rb
Rails.application.default_url_options = { host: 'staging.example.com', protocol: 'https://' }
Rails.application.configure do
# ...
end
# config/environments/production.rb
Rails.application.default_url_options = { host: 'www.example.com', protocol: 'https://' }
Rails.application.configure do
# ...
end
2. Dynamic solution
Configuring the correct hostname is quite annoying when you have multiple deployment targets with different hostnames, e.g. a staging server and a production server. Using the hack below you don't need to configure default url options for your mailers, as these are now derived from the request:
class ApplicationController < ActionController::Base
before_action :make_action_mailer_use_request_host_and_protocol
private
def make_action_mailer_use_request_host_and_protocol
ActionMailer::Base.default_url_options[:protocol] = request.protocol
ActionMailer::Base.default_url_options[:host] = request.host_with_port
end
end
If your application server talks only HTTP and relies on the web server for SSL, and if the web server is setting a special HTTPS forwarding header, Rails recognizes that a request originally was on HTTPS and will return the correct protocol.
Caveats:
- You need to harden your server setup to forbid the routing of a request with the
HOST
header to an application server, that serves requests under a different host e.g. your application serverexample.com
should not serve requests with theHOST
headerhacker.xyz
- You need to take care in your tests, that you reset
ActionMailer::Base.default_url_options
after e.g. request specs, e.g.spec/support/action_mailer.rb
:
RSpec.configure do |config|
config.around(type: :request) do |example|
url_options = ActionMailer::Base.default_url_options.dup
example.run
ActionMailer::Base.default_url_options = url_options
end
end