diff --git a/lib/devise/mailers/helpers.rb b/lib/devise/mailers/helpers.rb index 29a491970..0e22f8b89 100644 --- a/lib/devise/mailers/helpers.rb +++ b/lib/devise/mailers/helpers.rb @@ -41,6 +41,15 @@ def headers_for(action, opts) headers.delete(:from) if default_params[:from] headers.delete(:reply_to) if default_params[:reply_to] + # If this message expires, then specify the time Devise thinks it + # was sent and also when it expires. This may specify a second or + # two too late, not a problem. + expiry = expires_for(action) + if expiry + headers[:date] = Time.now + headers[:Expires] = (headers[:date] + expiry).rfc822() + end + headers.merge!(opts) @email = headers[:to] @@ -61,6 +70,11 @@ def template_paths template_path end + def expires_for(action) + return Devise.reset_password_within if action == :reset_password_instructions + nil + end + # Set up a subject doing an I18n lookup. At first, it attempts to set a subject # based on the current mapping: # diff --git a/test/mailers/reset_password_instructions_test.rb b/test/mailers/reset_password_instructions_test.rb index 5a344cbf0..5536bca49 100644 --- a/test/mailers/reset_password_instructions_test.rb +++ b/test/mailers/reset_password_instructions_test.rb @@ -80,6 +80,16 @@ def mail assert_match user.email, mail.body.encoded end + test 'headers should specify when the link expires' do + swap Devise, reset_password_within: 2.days do + expires = mail.header_fields.get_field("Expires") + assert_present expires + sent_at = DateTime.parse(mail.header_fields.get_field("Date").value) + validity = DateTime.parse(expires.value) - sent_at + assert_equal 2, validity + end + end + test 'body should have link to confirm the account' do host, port = ActionMailer::Base.default_url_options.values_at :host, :port