Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Bug Fixes:

* Regression: Preserve message-level charset when adding parts (related to Rails ActionMailer) @shields
* Regression: Adding a part should not reset the mail's charset to nil @railsbob
* Multipart::Body#extract_parts left the boundary delimiter's own trailing CRLF at the head of each subsequent part's raw_source instead of the part's actual content (RFC 2046 "dash-boundary transport-padding CRLF")

Performance:

Expand Down
8 changes: 7 additions & 1 deletion lib/mail/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,13 @@ def extract_parts
final_separator = parts[-2][1]
parts << [""] if final_separator != "--#{boundary}--"
end
parts.map(&:first)

# The CRLF that terminates a boundary delimiter line (RFC 2046: "dash-boundary
# transport-padding CRLF") is left dangling at the head of the content that
# follows, since the regex above only looks ahead at it without consuming it.
# Strip that one delimiter-owned line break so raw_source for each part after
# the first starts at its actual content, not the boundary's own line ending.
parts.map(&:first).each_with_index.map { |part, index| index > 0 ? part.sub(/\A\r?\n/, '') : part }
end

def crlf_boundary
Expand Down
9 changes: 9 additions & 0 deletions spec/mail/body_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ def assert_split_into(body, pre, epi, parts)
assert_split_into(multipart_body, "this is some text", "", 1)
end

it "should not leave the boundary's own line break at the head of each part's raw_source" do
multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n<p>This is HTML</p>\r\n------=_Part_2192_32400445--\r\n"
body = Mail::Body.new(multipart_body)
body.split!('----=_Part_2192_32400445')

expect(body.parts[0].raw_source).to eq "Content-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n"
expect(body.parts[1].raw_source).to eq "Content-Type: text/html\r\n\r\n<p>This is HTML</p>"
end

it "should keep the preamble text as its own preamble" do
multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n<p>This is HTML</p>\r\n------=_Part_2192_32400445--\r\n"
body = Mail::Body.new(multipart_body)
Expand Down