mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Allow for nested parts in multipart mails #1570 [Flurin Egger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1581 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
5651a69130
commit
5ddffc8c24
5 changed files with 98 additions and 32 deletions
|
@ -1,5 +1,7 @@
|
|||
*SVN*
|
||||
|
||||
* Allow for nested parts in multipart mails #1570 [Flurin Egger]
|
||||
|
||||
* Normalize line endings in outgoing mail bodies to "\n" #1536 [John Long]
|
||||
|
||||
* Allow template to be explicitly specified #1448 [tuxie@dekadance.se]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'action_mailer/adv_attr_accessor'
|
||||
require 'action_mailer/part'
|
||||
require 'action_mailer/part_container'
|
||||
require 'tmail/net'
|
||||
|
||||
module ActionMailer #:nodoc:
|
||||
|
@ -108,6 +109,7 @@ module ActionMailer #:nodoc:
|
|||
# pick a different charset from inside a method with <tt>@charset</tt>.
|
||||
class Base
|
||||
include ActionMailer::AdvAttrAccessor
|
||||
include ActionMailer::PartContainer
|
||||
|
||||
private_class_method :new #:nodoc:
|
||||
|
||||
|
@ -220,25 +222,6 @@ module ActionMailer #:nodoc:
|
|||
return @mail
|
||||
end
|
||||
|
||||
# Add a part to a multipart message, with the given content-type. The
|
||||
# part itself is yielded to the block, so that other properties (charset,
|
||||
# body, headers, etc.) can be set on it.
|
||||
def part(params)
|
||||
params = {:content_type => params} if String === params
|
||||
part = Part.new(params)
|
||||
yield part if block_given?
|
||||
@parts << part
|
||||
end
|
||||
|
||||
# Add an attachment to a multipart message. This is simply a part with the
|
||||
# content-disposition set to "attachment".
|
||||
def attachment(params, &block)
|
||||
params = { :content_type => params } if String === params
|
||||
params = { :disposition => "attachment",
|
||||
:transfer_encoding => "base64" }.merge(params)
|
||||
part(params, &block)
|
||||
end
|
||||
|
||||
private
|
||||
def render_message(method_name, body)
|
||||
initialize_template_class(body).render_file(method_name)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
require 'action_mailer/adv_attr_accessor'
|
||||
require 'action_mailer/part_container'
|
||||
|
||||
module ActionMailer
|
||||
|
||||
class Part #:nodoc:
|
||||
include ActionMailer::AdvAttrAccessor
|
||||
include ActionMailer::PartContainer
|
||||
|
||||
adv_attr_accessor :content_type, :content_disposition, :charset, :body
|
||||
adv_attr_accessor :filename, :transfer_encoding, :headers
|
||||
|
@ -16,27 +18,54 @@ module ActionMailer
|
|||
@filename = params[:filename]
|
||||
@transfer_encoding = params[:transfer_encoding] || "quoted-printable"
|
||||
@headers = params[:headers] || {}
|
||||
@parts = []
|
||||
end
|
||||
|
||||
def to_mail(defaults)
|
||||
part = TMail::Mail.new
|
||||
part.set_content_type(content_type || defaults.content_type, nil,
|
||||
"charset" => (content_disposition == "attachment" ?
|
||||
nil : (charset || defaults.charset)),
|
||||
"name" => filename)
|
||||
part.set_content_disposition(content_disposition,
|
||||
"filename" => filename)
|
||||
|
||||
part.content_transfer_encoding = transfer_encoding || "quoted-printable"
|
||||
case (transfer_encoding || "").downcase
|
||||
when "base64" then
|
||||
part.body = TMail::Base64.folding_encode(body)
|
||||
when "quoted-printable"
|
||||
part.body = [body].pack("M*")
|
||||
if @parts.empty?
|
||||
part.content_transfer_encoding = transfer_encoding || "quoted-printable"
|
||||
case (transfer_encoding || "").downcase
|
||||
when "base64" then
|
||||
part.body = TMail::Base64.folding_encode(body)
|
||||
when "quoted-printable"
|
||||
part.body = [body].pack("M*")
|
||||
else
|
||||
part.body = body
|
||||
end
|
||||
|
||||
# Always set the content_type after setting the body and or parts!
|
||||
# Also don't set filename and name when there is none (like in
|
||||
# non-attachment parts)
|
||||
if content_disposition == "attachment"
|
||||
part.set_content_type(content_type || defaults.content_type, nil,
|
||||
"charset" => nil,
|
||||
"name" => filename)
|
||||
part.set_content_disposition(content_disposition, "filename" => filename)
|
||||
else
|
||||
part.set_content_type(content_type || defaults.content_type, nil,
|
||||
"charset" => (charset || defaults.charset))
|
||||
part.set_content_disposition(content_disposition)
|
||||
end
|
||||
else
|
||||
if String === body
|
||||
part = TMail::Mail.new
|
||||
part.body = body
|
||||
part.set_content_type content_type, nil, { "charset" => charset }
|
||||
part.set_content_disposition "inline"
|
||||
m.parts << part
|
||||
end
|
||||
|
||||
@parts.each do |p|
|
||||
prt = (TMail::Mail === p ? p : p.to_mail(defaults))
|
||||
part.parts << prt
|
||||
end
|
||||
|
||||
part.set_content_type(content_type, nil, { "charset" => charset }) if content_type =~ /multipart/
|
||||
end
|
||||
|
||||
|
||||
|
||||
part
|
||||
end
|
||||
end
|
||||
|
|
25
actionmailer/lib/action_mailer/part_container.rb
Normal file
25
actionmailer/lib/action_mailer/part_container.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
module ActionMailer
|
||||
module PartContainer
|
||||
attr_reader :parts
|
||||
|
||||
# Add a part to a multipart message, with the given content-type. The
|
||||
# part itself is yielded to the block, so that other properties (charset,
|
||||
# body, headers, etc.) can be set on it.
|
||||
def part(params)
|
||||
params = {:content_type => params} if String === params
|
||||
part = Part.new(params)
|
||||
yield part if block_given?
|
||||
@parts << part
|
||||
end
|
||||
|
||||
# Add an attachment to a multipart message. This is simply a part with the
|
||||
# content-disposition set to "attachment".
|
||||
def attachment(params, &block)
|
||||
params = { :content_type => params } if String === params
|
||||
params = { :disposition => "attachment",
|
||||
:transfer_encoding => "base64" }.merge(params)
|
||||
part(params, &block)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -145,6 +145,20 @@ class TestMailer < ActionMailer::Base
|
|||
"line #5\n\nline#6\r\n\r\nline #7"
|
||||
end
|
||||
|
||||
def nested_multipart(recipient)
|
||||
recipients recipient
|
||||
subject "nested multipart"
|
||||
from "test@example.com"
|
||||
content_type "multipart/mixed"
|
||||
part :content_type => "multipart/alternative", :content_disposition => "inline" do |p|
|
||||
p.part :content_type => "text/plain", :body => "test text\nline #2"
|
||||
p.part :content_type => "text/html", :body => "<b>test</b> HTML<br/>\nline #2"
|
||||
end
|
||||
attachment :content_type => "application/octet-stream",:filename => "test.txt", :body => "test abcdefghijklmnopqstuvwxyz"
|
||||
|
||||
end
|
||||
|
||||
|
||||
class <<self
|
||||
attr_accessor :received_body
|
||||
end
|
||||
|
@ -179,6 +193,19 @@ class ActionMailerTest < Test::Unit::TestCase
|
|||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def test_nested_parts
|
||||
created = nil
|
||||
assert_nothing_raised { created = TestMailer.create_nested_multipart(@recipient)}
|
||||
assert_equal 2,created.parts.size
|
||||
assert_equal 2,created.parts.first.parts.size
|
||||
|
||||
assert_equal "multipart/mixed", created.content_type
|
||||
assert_equal "multipart/alternative", created.parts.first.content_type
|
||||
assert_equal "text/plain", created.parts.first.parts.first.content_type
|
||||
assert_equal "text/html", created.parts.first.parts[1].content_type
|
||||
assert_equal "application/octet-stream", created.parts[1].content_type
|
||||
end
|
||||
|
||||
def test_signed_up
|
||||
expected = new_mail
|
||||
expected.to = @recipient
|
||||
|
|
Loading…
Reference in a new issue