diff options
Diffstat (limited to 'actionmailer')
26 files changed, 223 insertions, 76 deletions
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index d8636fd83d..5dc7a33f55 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -1,3 +1,15 @@ +*2.3.0 [Edge]* + +* Fixed RFC-2045 quoted-printable bug #1421 [squadette] + +* Fixed that no body charset would be set when there are attachments present #740 [Paweł Kondzior] + + +*2.2.1 [RC2] (November 14th, 2008)* + +* Turn on STARTTLS if it is available in Net::SMTP (added in Ruby 1.8.7) and the SMTP server supports it (This is required for Gmail's SMTP server) #1336 [Grant Hollingworth] + + *2.2.0 [RC1] (October 24th, 2008)* * Add layout functionality to mailers [Pratik] diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index 9f4a387126..c3826e3a27 100644 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s| s.rubyforge_project = "actionmailer" s.homepage = "http://www.rubyonrails.org" - s.add_dependency('actionpack', '= 2.2.0' + PKG_BUILD) + s.add_dependency('actionpack', '= 2.3.0' + PKG_BUILD) s.has_rdoc = true s.requirements << 'none' diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index 2a9210deb9..0f173ea4e8 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -31,22 +31,31 @@ rescue LoadError end end -require 'action_mailer/vendor' -require 'tmail' +require 'action_view' -require 'action_mailer/base' -require 'action_mailer/helpers' -require 'action_mailer/mail_helper' -require 'action_mailer/quoting' -require 'action_mailer/test_helper' +module ActionMailer + def self.load_all! + [Base, Part, ::Text::Format, ::Net::SMTP] + end -require 'net/smtp' + autoload :AdvAttrAccessor, 'action_mailer/adv_attr_accessor' + autoload :Base, 'action_mailer/base' + autoload :Helpers, 'action_mailer/helpers' + autoload :Part, 'action_mailer/part' + autoload :PartContainer, 'action_mailer/part_container' + autoload :Quoting, 'action_mailer/quoting' + autoload :TestCase, 'action_mailer/test_case' + autoload :TestHelper, 'action_mailer/test_helper' + autoload :Utils, 'action_mailer/utils' +end -ActionMailer::Base.class_eval do - include ActionMailer::Quoting - include ActionMailer::Helpers +module Text + autoload :Format, 'action_mailer/vendor/text_format' +end - helper MailHelper +module Net + autoload :SMTP, 'net/smtp' end -silence_warnings { TMail::Encoder.const_set("MAX_LINE_LEN", 200) } +autoload :MailHelper, 'action_mailer/mail_helper' +autoload :TMail, 'action_mailer/vendor/tmail' diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 043f56ba17..730dd2d7aa 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,9 +1,3 @@ -require 'action_mailer/adv_attr_accessor' -require 'action_mailer/part' -require 'action_mailer/part_container' -require 'action_mailer/utils' -require 'tmail/net' - module ActionMailer #:nodoc: # Action Mailer allows you to send email from your application using a mailer model and views. # @@ -245,7 +239,7 @@ module ActionMailer #:nodoc: # and appear last in the mime encoded message. You can also pick a different order from inside a method with # +implicit_parts_order+. class Base - include AdvAttrAccessor, PartContainer + include AdvAttrAccessor, PartContainer, Quoting, Utils if Object.const_defined?(:ActionController) include ActionController::UrlWriter include ActionController::Layout @@ -386,12 +380,15 @@ module ActionMailer #:nodoc: end def method_missing(method_symbol, *parameters) #:nodoc: - match = matches_dynamic_method?(method_symbol) - case match[1] - when 'create' then new(match[2], *parameters).mail - when 'deliver' then new(match[2], *parameters).deliver! - when 'new' then nil - else super + if match = matches_dynamic_method?(method_symbol) + case match[1] + when 'create' then new(match[2], *parameters).mail + when 'deliver' then new(match[2], *parameters).deliver! + when 'new' then nil + else super + end + else + super end end @@ -423,12 +420,6 @@ module ActionMailer #:nodoc: new.deliver!(mail) end - def register_template_extension(extension) - ActiveSupport::Deprecation.warn( - "ActionMailer::Base.register_template_extension has been deprecated." + - "Use ActionView::Base.register_template_extension instead", caller) - end - def template_root self.view_paths && self.view_paths.first end @@ -440,7 +431,7 @@ module ActionMailer #:nodoc: private def matches_dynamic_method?(method_name) #:nodoc: method_name = method_name.to_s - /(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name) + /^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name) end end @@ -546,7 +537,12 @@ module ActionMailer #:nodoc: end def render_message(method_name, body) + if method_name.respond_to?(:content_type) + @current_template_content_type = method_name.content_type + end render :file => method_name, :body => body + ensure + @current_template_content_type = nil end def render(opts) @@ -565,7 +561,11 @@ module ActionMailer #:nodoc: end def default_template_format - :html + if @current_template_content_type + Mime::Type.lookup(@current_template_content_type).to_sym + else + :html + end end def candidate_for_layout?(options) @@ -585,7 +585,9 @@ module ActionMailer #:nodoc: end def initialize_template_class(assigns) - ActionView::Base.new(view_paths, assigns, self) + template = ActionView::Base.new(view_paths, assigns, self) + template.template_format = default_template_format + template end def sort_parts(parts, order = []) @@ -634,11 +636,11 @@ module ActionMailer #:nodoc: if @parts.empty? m.set_content_type(real_content_type, nil, ctype_attrs) - m.body = Utils.normalize_new_lines(body) + m.body = normalize_new_lines(body) else if String === body part = TMail::Mail.new - part.body = Utils.normalize_new_lines(body) + part.body = normalize_new_lines(body) part.set_content_type(real_content_type, nil, ctype_attrs) part.set_content_disposition "inline" m.parts << part @@ -663,8 +665,10 @@ module ActionMailer #:nodoc: mail.ready_to_send sender = mail['return-path'] || mail.from - Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain], - smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp| + smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port]) + smtp.enable_starttls_auto if smtp.respond_to?(:enable_starttls_auto) + smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password], + smtp_settings[:authentication]) do |smtp| smtp.sendmail(mail.encoded, sender, destinations) end end @@ -682,4 +686,9 @@ module ActionMailer #:nodoc: deliveries << mail end end + + Base.class_eval do + include Helpers + helper MailHelper + end end diff --git a/actionmailer/lib/action_mailer/helpers.rb b/actionmailer/lib/action_mailer/helpers.rb index 5f6dcd77cd..31f7de8d60 100644 --- a/actionmailer/lib/action_mailer/helpers.rb +++ b/actionmailer/lib/action_mailer/helpers.rb @@ -1,3 +1,5 @@ +require 'active_support/dependencies' + module ActionMailer module Helpers #:nodoc: def self.included(base) #:nodoc: diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb index 11fd7d77e0..351b966abe 100644 --- a/actionmailer/lib/action_mailer/mail_helper.rb +++ b/actionmailer/lib/action_mailer/mail_helper.rb @@ -1,5 +1,3 @@ -require 'text/format' - module MailHelper # Uses Text::Format to take the text and format it, indented two spaces for # each line, and wrapped at 72 columns. diff --git a/actionmailer/lib/action_mailer/part.rb b/actionmailer/lib/action_mailer/part.rb index 2dabf15f08..977c0b2b5c 100644 --- a/actionmailer/lib/action_mailer/part.rb +++ b/actionmailer/lib/action_mailer/part.rb @@ -1,15 +1,10 @@ -require 'action_mailer/adv_attr_accessor' -require 'action_mailer/part_container' -require 'action_mailer/utils' - module ActionMailer # Represents a subpart of an email message. It shares many similar # attributes of ActionMailer::Base. Although you can create parts manually # and add them to the +parts+ list of the mailer, it is easier # to use the helper methods in ActionMailer::PartContainer. class Part - include ActionMailer::AdvAttrAccessor - include ActionMailer::PartContainer + include AdvAttrAccessor, PartContainer, Utils # Represents the body of the part, as a string. This should not be a # Hash (like ActionMailer::Base), but if you want a template to be rendered @@ -64,7 +59,7 @@ module ActionMailer when "base64" then part.body = TMail::Base64.folding_encode(body) when "quoted-printable" - part.body = [Utils.normalize_new_lines(body)].pack("M*") + part.body = [normalize_new_lines(body)].pack("M*") else part.body = body end @@ -102,7 +97,6 @@ module ActionMailer end private - def squish(values={}) values.delete_if { |k,v| v.nil? } end diff --git a/actionmailer/lib/action_mailer/part_container.rb b/actionmailer/lib/action_mailer/part_container.rb index 3e3d6b9d4f..abfd8f8426 100644 --- a/actionmailer/lib/action_mailer/part_container.rb +++ b/actionmailer/lib/action_mailer/part_container.rb @@ -41,7 +41,11 @@ module ActionMailer private def parse_content_type(defaults=nil) - return [defaults && defaults.content_type, {}] if content_type.blank? + if content_type.blank? + return defaults ? + [ defaults.content_type, { 'charset' => defaults.charset } ] : + [ nil, {} ] + end ctype, *attrs = content_type.split(/;\s*/) attrs = attrs.inject({}) { |h,s| k,v = s.split(/=/, 2); h[k] = v; h } [ctype, {"charset" => charset || defaults && defaults.charset}.merge(attrs)] diff --git a/actionmailer/lib/action_mailer/quoting.rb b/actionmailer/lib/action_mailer/quoting.rb index a2f2c70799..94fa042002 100644 --- a/actionmailer/lib/action_mailer/quoting.rb +++ b/actionmailer/lib/action_mailer/quoting.rb @@ -12,7 +12,7 @@ module ActionMailer # account multi-byte characters (if executing with $KCODE="u", for instance) def quoted_printable_encode(character) result = "" - character.each_byte { |b| result << "=%02x" % b } + character.each_byte { |b| result << "=%02X" % b } result end diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb index d474afe3a2..8035db6f03 100644 --- a/actionmailer/lib/action_mailer/test_case.rb +++ b/actionmailer/lib/action_mailer/test_case.rb @@ -10,7 +10,7 @@ module ActionMailer end class TestCase < ActiveSupport::TestCase - include ActionMailer::Quoting + include Quoting, TestHelper setup :initialize_test_deliveries setup :set_expected_mail diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb index 3a1612442f..f234c0248c 100644 --- a/actionmailer/lib/action_mailer/test_helper.rb +++ b/actionmailer/lib/action_mailer/test_helper.rb @@ -58,6 +58,7 @@ module ActionMailer end end +# TODO: Deprecate this module Test module Unit class TestCase diff --git a/actionmailer/lib/action_mailer/utils.rb b/actionmailer/lib/action_mailer/utils.rb index 552f695a92..26d2e60aaf 100644 --- a/actionmailer/lib/action_mailer/utils.rb +++ b/actionmailer/lib/action_mailer/utils.rb @@ -3,6 +3,5 @@ module ActionMailer def normalize_new_lines(text) text.to_s.gsub(/\r\n?/, "\n") end - module_function :normalize_new_lines end end diff --git a/actionmailer/lib/action_mailer/vendor.rb b/actionmailer/lib/action_mailer/vendor.rb deleted file mode 100644 index 7a20e9bd6e..0000000000 --- a/actionmailer/lib/action_mailer/vendor.rb +++ /dev/null @@ -1,14 +0,0 @@ -# Prefer gems to the bundled libs. -require 'rubygems' - -begin - gem 'tmail', '~> 1.2.3' -rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.3" -end - -begin - gem 'text-format', '>= 0.6.3' -rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/text-format-0.6.3" -end diff --git a/actionmailer/lib/action_mailer/vendor/text_format.rb b/actionmailer/lib/action_mailer/vendor/text_format.rb new file mode 100644 index 0000000000..c6c8c394d0 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/text_format.rb @@ -0,0 +1,10 @@ +# Prefer gems to the bundled libs. +require 'rubygems' + +begin + gem 'text-format', '>= 0.6.3' +rescue Gem::LoadError + $:.unshift "#{File.dirname(__FILE__)}/text-format-0.6.3" +end + +require 'text/format' diff --git a/actionmailer/lib/action_mailer/vendor/tmail.rb b/actionmailer/lib/action_mailer/vendor/tmail.rb new file mode 100644 index 0000000000..51d36cdd0d --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail.rb @@ -0,0 +1,17 @@ +# Prefer gems to the bundled libs. +require 'rubygems' + +begin + gem 'tmail', '~> 1.2.3' +rescue Gem::LoadError + $:.unshift "#{File.dirname(__FILE__)}/tmail-1.2.3" +end + +module TMail +end + +require 'tmail' + +silence_warnings do + TMail::Encoder.const_set("MAX_LINE_LEN", 200) +end diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb index 9728d1b4db..9cd7a14b73 100644 --- a/actionmailer/lib/action_mailer/version.rb +++ b/actionmailer/lib/action_mailer/version.rb @@ -1,7 +1,7 @@ module ActionMailer module VERSION #:nodoc: MAJOR = 2 - MINOR = 2 + MINOR = 3 TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index 905f25c9f7..1617b88c8e 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -24,11 +24,15 @@ class MockSMTP def sendmail(mail, from, to) @@deliveries << [mail, from, to] end + + def start(*args) + yield self + end end class Net::SMTP - def self.start(*args) - yield MockSMTP.new + def self.new(*args) + MockSMTP.new end end diff --git a/actionmailer/test/asset_host_test.rb b/actionmailer/test/asset_host_test.rb new file mode 100644 index 0000000000..1c92dd266d --- /dev/null +++ b/actionmailer/test/asset_host_test.rb @@ -0,0 +1,54 @@ +require 'abstract_unit' + +class AssetHostMailer < ActionMailer::Base + def email_with_asset(recipient) + recipients recipient + subject "testing email containing asset path while asset_host is set" + from "tester@example.com" + end +end + +class AssetHostTest < Test::Unit::TestCase + def setup + set_delivery_method :test + ActionMailer::Base.perform_deliveries = true + ActionMailer::Base.deliveries = [] + + @recipient = 'test@localhost' + end + + def teardown + restore_delivery_method + end + + def test_asset_host_as_string + ActionController::Base.asset_host = "http://www.example.com" + mail = AssetHostMailer.deliver_email_with_asset(@recipient) + assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.strip + end + + def test_asset_host_as_one_arguement_proc + ActionController::Base.asset_host = Proc.new { |source| + if source.starts_with?('/images') + "http://images.example.com" + else + "http://assets.example.com" + end + } + mail = AssetHostMailer.deliver_email_with_asset(@recipient) + assert_equal "<img alt=\"Somelogo\" src=\"http://images.example.com/images/somelogo.png\" />", mail.body.strip + end + + def test_asset_host_as_two_arguement_proc + ActionController::Base.asset_host = Proc.new {|source,request| + if request && request.ssl? + "https://www.example.com" + else + "http://www.example.com" + end + } + mail = nil + assert_nothing_raised { mail = AssetHostMailer.deliver_email_with_asset(@recipient) } + assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.strip + end +end
\ No newline at end of file diff --git a/actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb b/actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb new file mode 100644 index 0000000000..b3f0438d03 --- /dev/null +++ b/actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb @@ -0,0 +1 @@ +<%= image_tag "somelogo.png" %>
\ No newline at end of file diff --git a/actionmailer/test/fixtures/auto_layout_mailer/multipart.text.html.erb b/actionmailer/test/fixtures/auto_layout_mailer/multipart.text.html.erb new file mode 100644 index 0000000000..6d73f199c4 --- /dev/null +++ b/actionmailer/test/fixtures/auto_layout_mailer/multipart.text.html.erb @@ -0,0 +1 @@ +text/html multipart
\ No newline at end of file diff --git a/actionmailer/test/fixtures/auto_layout_mailer/multipart.text.plain.erb b/actionmailer/test/fixtures/auto_layout_mailer/multipart.text.plain.erb new file mode 100644 index 0000000000..f4b91e4031 --- /dev/null +++ b/actionmailer/test/fixtures/auto_layout_mailer/multipart.text.plain.erb @@ -0,0 +1 @@ +text/plain multipart
\ No newline at end of file diff --git a/actionmailer/test/fixtures/layouts/auto_layout_mailer.text.erb b/actionmailer/test/fixtures/layouts/auto_layout_mailer.text.erb new file mode 100644 index 0000000000..111576b672 --- /dev/null +++ b/actionmailer/test/fixtures/layouts/auto_layout_mailer.text.erb @@ -0,0 +1 @@ +text/plain layout - <%= yield %>
\ No newline at end of file diff --git a/actionmailer/test/mail_layout_test.rb b/actionmailer/test/mail_layout_test.rb index ffba9a16bd..c185bd5acd 100644 --- a/actionmailer/test/mail_layout_test.rb +++ b/actionmailer/test/mail_layout_test.rb @@ -20,6 +20,12 @@ class AutoLayoutMailer < ActionMailer::Base from "tester@example.com" body render(:inline => "Hello, <%= @world %>", :layout => false, :body => { :world => "Earth" }) end + + def multipart(recipient) + recipients recipient + subject "You have a mail" + from "tester@example.com" + end end class ExplicitLayoutMailer < ActionMailer::Base @@ -56,6 +62,17 @@ class LayoutMailerTest < Test::Unit::TestCase assert_equal "Hello from layout Inside", mail.body.strip end + def test_should_pickup_multipart_layout + mail = AutoLayoutMailer.create_multipart(@recipient) + assert_equal 2, mail.parts.size + + assert_equal 'text/plain', mail.parts.first.content_type + assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body + + assert_equal 'text/html', mail.parts.last.content_type + assert_equal "Hello from layout text/html multipart", mail.parts.last.body + end + def test_should_pickup_layout_given_to_render mail = AutoLayoutMailer.create_spam(@recipient) assert_equal "Spammer layout Hello, Earth", mail.body.strip diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb index 7f9540c44b..c49049cc6a 100644 --- a/actionmailer/test/mail_service_test.rb +++ b/actionmailer/test/mail_service_test.rb @@ -915,6 +915,8 @@ EOF def test_multipart_with_template_path_with_dots mail = FunkyPathMailer.create_multipart_with_template_path_with_dots(@recipient) assert_equal 2, mail.parts.length + assert_equal 'text/plain', mail.parts[0].content_type + assert_equal 'utf-8', mail.parts[0].charset end def test_custom_content_type_attributes @@ -938,6 +940,20 @@ EOF mail = TestMailer.create_body_ivar(@recipient) assert_equal "body: foo\nbar: baz", mail.body end + + def test_starttls_is_enabled_if_supported + MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(true) + MockSMTP.any_instance.expects(:enable_starttls_auto) + ActionMailer::Base.delivery_method = :smtp + TestMailer.deliver_signed_up(@recipient) + end + + def test_starttls_is_disabled_if_not_supported + MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(false) + MockSMTP.any_instance.expects(:enable_starttls_auto).never + ActionMailer::Base.delivery_method = :smtp + TestMailer.deliver_signed_up(@recipient) + end end end # uses_mocha @@ -1031,4 +1047,16 @@ class RespondToTest < Test::Unit::TestCase def test_should_not_respond_to_deliver_with_template_suffix_if_it_begins_with_a_digit assert !RespondToMailer.respond_to?(:deliver_1_template) end + + def test_should_not_respond_to_method_where_deliver_is_not_a_suffix + assert !RespondToMailer.respond_to?(:foo_deliver_template) + end + + def test_should_still_raise_exception_with_expected_message_when_calling_an_undefined_method + error = assert_raises NoMethodError do + RespondToMailer.not_a_method + end + + assert_match /undefined method.*not_a_method/, error.message + end end diff --git a/actionmailer/test/quoting_test.rb b/actionmailer/test/quoting_test.rb index 13a859a5cc..2650efccdb 100644 --- a/actionmailer/test/quoting_test.rb +++ b/actionmailer/test/quoting_test.rb @@ -1,6 +1,5 @@ # encoding: utf-8 require 'abstract_unit' -require 'tmail' require 'tempfile' class QuotingTest < Test::Unit::TestCase diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb index f8913e548c..9d22bb26bd 100644 --- a/actionmailer/test/test_helper_test.rb +++ b/actionmailer/test/test_helper_test.rb @@ -36,7 +36,7 @@ class TestHelperMailerTest < ActionMailer::TestCase end def test_encode - assert_equal "=?utf-8?Q?=0aasdf=0a?=", encode("\nasdf\n") + assert_equal "=?utf-8?Q?=0Aasdf=0A?=", encode("\nasdf\n") end def test_assert_emails @@ -84,7 +84,7 @@ class TestHelperMailerTest < ActionMailer::TestCase end def test_assert_emails_too_few_sent - error = assert_raises Test::Unit::AssertionFailedError do + error = assert_raises ActiveSupport::TestCase::Assertion do assert_emails 2 do TestHelperMailer.deliver_test end @@ -94,7 +94,7 @@ class TestHelperMailerTest < ActionMailer::TestCase end def test_assert_emails_too_many_sent - error = assert_raises Test::Unit::AssertionFailedError do + error = assert_raises ActiveSupport::TestCase::Assertion do assert_emails 1 do TestHelperMailer.deliver_test TestHelperMailer.deliver_test @@ -105,7 +105,7 @@ class TestHelperMailerTest < ActionMailer::TestCase end def test_assert_no_emails_failure - error = assert_raises Test::Unit::AssertionFailedError do + error = assert_raises ActiveSupport::TestCase::Assertion do assert_no_emails do TestHelperMailer.deliver_test end |