Skip to content

Commit 401b4e5

Browse files
author
Lauren Oliveri
committed
Handle edge case when inline image attachment part is missing a filename
Fixes #1329 First attempt at a fix: #1332 In this second attempt, I tried to scope down the issue to where the issue appears most probable: inline images. We do not add a default filename for the nameless attachment, rather just ensure that the message part is considered an attachment if it is an inline image.
1 parent aba0b5f commit 401b4e5

File tree

6 files changed

+118
-8
lines changed

6 files changed

+118
-8
lines changed

CHANGELOG.rdoc

+2
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ Compatibility:
1717
Features:
1818
* Message#inspect_structure and PartsList#inspect_structure pretty-print the hierarchy of message parts. (TylerRick)
1919

20+
Bugs:
21+
* Handle case when inline image attachment parts do not contain a filename or Content-Location header. (lao9)
2022

2123
Please check [2-7-stable](https://github.com/mikel/mail/blob/2-7-stable/CHANGELOG.rdoc) for previous changes.

lib/mail/message.rb

+11-3
Original file line numberDiff line numberDiff line change
@@ -1911,7 +1911,7 @@ def decode_body
19111911
# Returns true if this part is an attachment,
19121912
# false otherwise.
19131913
def attachment?
1914-
!!find_attachment
1914+
!!find_attachment_name || inline_image?
19151915
end
19161916

19171917
# Returns the attachment data if there is any
@@ -1921,7 +1921,7 @@ def attachment
19211921

19221922
# Returns the filename of the attachment
19231923
def filename
1924-
find_attachment
1924+
find_attachment_name
19251925
end
19261926

19271927
def all_parts
@@ -2117,7 +2117,7 @@ def init_with_string(string)
21172117
end
21182118

21192119
# Returns the filename of the attachment (if it exists) or returns nil
2120-
def find_attachment
2120+
def find_attachment_name
21212121
content_type_name = header[:content_type].filename rescue nil
21222122
content_disp_name = header[:content_disposition].filename rescue nil
21232123
content_loc_name = header[:content_location].location rescue nil
@@ -2135,6 +2135,14 @@ def find_attachment
21352135
filename
21362136
end
21372137

2138+
def inline_image?
2139+
image? && inline?
2140+
end
2141+
2142+
def image?
2143+
header[:content_type] && header[:content_type].main_type == "image"
2144+
end
2145+
21382146
def do_delivery
21392147
begin
21402148
if perform_deliveries
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Mime-Version: 1.0 (Apple Message framework v730)
2+
Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151
3+
Message-Id: <[email protected]>
4+
5+
Subject: testing
6+
Date: Mon, 6 Jun 2005 22:21:22 +0200
7+
8+
9+
10+
--Apple-Mail-13-196941151
11+
Content-Transfer-Encoding: quoted-printable
12+
Content-Type: text/plain;
13+
charset=ISO-8859-1;
14+
delsp=yes;
15+
format=flowed
16+
17+
This is the first part.
18+
19+
--Apple-Mail-13-196941151
20+
Content-Type: image/jpeg
21+
Content-Transfer-Encoding: base64
22+
Content-ID: <qbFGyPQAS8>
23+
Content-Disposition: inline
24+
25+
jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw
26+
ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE
27+
QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB
28+
gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5=
29+
30+
--Apple-Mail-13-196941151--
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Mime-Version: 1.0 (Apple Message framework v730)
2+
Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151
3+
Message-Id: <[email protected]>
4+
5+
Subject: testing
6+
Date: Mon, 6 Jun 2005 22:21:22 +0200
7+
8+
9+
10+
--Apple-Mail-13-196941151
11+
Content-Transfer-Encoding: quoted-printable
12+
Content-Type: text/plain;
13+
charset=ISO-8859-1;
14+
delsp=yes;
15+
format=flowed
16+
17+
This is the first part.
18+
19+
--Apple-Mail-13-196941151
20+
Content-Type: image/jpeg; filename="Photo25.jpg"
21+
Content-Transfer-Encoding: base64
22+
Content-ID: <qbFGyPQAS8>
23+
Content-Disposition: inline
24+
25+
jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw
26+
ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE
27+
QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB
28+
gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5=
29+
30+
--Apple-Mail-13-196941151--

spec/mail/attachments_list_spec.rb

+5
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ def check_decoded(actual, expected)
239239
expect(mail.attachments[0].filename).to eq 'api.rb'
240240
end
241241

242+
it "should not need filename for inline attachments" do
243+
mail = read_fixture('emails/attachment_emails/attachment_missing_filename.eml')
244+
expect(mail.attachments.length).to eq 1
245+
end
246+
242247
it "should decode an attachment" do
243248
mail = read_fixture('emails/attachment_emails/attachment_pdf.eml')
244249
expect(mail.attachments[0].decoded.length).to eq 1026

spec/mail/message_spec.rb

+40-5
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ def message_headers_should_match(message, other)
14391439
part.body = 'a' * 999
14401440
end
14411441
mail.encoded
1442-
1442+
14431443
expect(mail.parts.count).to eq(1)
14441444
expect(mail.parts.last.content_transfer_encoding).to match(/7bit|8bit|binary/)
14451445
end
@@ -1459,19 +1459,19 @@ def message_headers_should_match(message, other)
14591459
end
14601460
end
14611461
end
1462-
1462+
14631463
it "should not add an empty charset header" do
14641464
@mail.charset = nil
1465-
1465+
14661466
expect(@mail.multipart?).to eq true
14671467
expect(@mail.parts.count).to eq 2
14681468
expect(@mail.encoded.scan(/charset=UTF-8/).count).to eq 2
14691469
end
1470-
1470+
14711471
it "should remove the charset header" do
14721472
@mail.charset = 'iso-8859-1'
14731473
@mail.charset = nil
1474-
1474+
14751475
expect(@mail.encoded.scan(/charset=UTF-8/).count).to eq 2
14761476
expect(@mail.encoded.scan(/charset=iso-8859-1/).count).to eq 0
14771477
end
@@ -1495,6 +1495,41 @@ def message_headers_should_match(message, other)
14951495
end
14961496
end
14971497

1498+
describe "attachment?" do
1499+
context "with content location" do
1500+
subject do
1501+
read_fixture('emails', 'attachment_emails', 'attachment_content_location.eml')
1502+
end
1503+
1504+
it "returns true using the content location filename" do
1505+
expect(subject.parts[0].attachment?).to eq(false)
1506+
expect(subject.parts[1].attachment?).to eq(true)
1507+
end
1508+
end
1509+
1510+
context "with content type filename" do
1511+
subject do
1512+
read_fixture('emails', 'attachment_emails', 'attachment_with_filename.eml')
1513+
end
1514+
1515+
it "returns true using the content type filename" do
1516+
expect(subject.parts[0].attachment?).to eq(false)
1517+
expect(subject.parts[1].attachment?).to eq(true)
1518+
end
1519+
end
1520+
1521+
context "without content location or filename" do
1522+
subject do
1523+
read_fixture('emails', 'attachment_emails', 'attachment_missing_filename.eml')
1524+
end
1525+
1526+
it "returns true for the inline attachment" do
1527+
expect(subject.parts[0].attachment?).to eq(false)
1528+
expect(subject.parts[1].attachment?).to eq(true)
1529+
end
1530+
end
1531+
end
1532+
14981533
describe "content-transfer-encoding" do
14991534

15001535
it "should use 7bit for only US-ASCII chars" do

0 commit comments

Comments
 (0)