Skip to content

Commit

Permalink
Added recursive parsing of attachments inside message/rfc822 parts.
Browse files Browse the repository at this point in the history
  • Loading branch information
Bira authored and mikel committed May 7, 2010
1 parent 824d933 commit 1e665e4
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 19 deletions.
20 changes: 11 additions & 9 deletions lib/mail/attachments_list.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
module Mail
class AttachmentsList < Array

def initialize(parts_list)
@parts_list = parts_list
parts_list.map { |p|
if p.parts.empty?
if p.content_type == "message/rfc822"

This comment has been minimized.

Copy link
@pdg137

pdg137 May 19, 2016

Shouldn't this be checking p.mime_type instead of p.content_type? It will be thrown off by any extra details in the header, like charset, or maybe even whitespace.

Mail.new(p.body).attachments
elsif p.parts.empty?
p if p.attachment?
else
p.attachments
end
}.flatten.compact.each { |a| self << a }
self
end

# Returns the attachment by filename or at index.
#
#
# mail.attachments['test.png'] = File.read('test.png')
# mail.attachments['test.jpg'] = File.read('test.jpg')
#
#
# mail.attachments['test.png'].filename #=> 'test.png'
# mail.attachments[1].filename #=> 'test.jpg'
def [](index_value)
Expand Down Expand Up @@ -68,7 +70,7 @@ def []=(name, value)

@parts_list << Part.new(hash)
end

# Uses the mime type to try and guess the encoding, if it is a binary type, or unknown, then we
# set it to binary, otherwise as set to plain text
def guess_encoding
Expand All @@ -77,8 +79,8 @@ def guess_encoding
else
"binary"
end
end
end

def set_mime_type(filename)
# Have to do this because MIME::Types is not Ruby 1.9 safe yet
if RUBY_VERSION >= '1.9'
Expand All @@ -88,7 +90,7 @@ def set_mime_type(filename)
end
@mime_type = MIME::Types.type_for(filename).first
end

end
end

Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
Mime-Version: 1.0 (Apple Message framework v730)
Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151
Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com>
From: foo@example.com
Subject: testing
Date: Mon, 6 Jun 2005 22:21:22 +0200
To: blah@example.com


--Apple-Mail-13-196941151
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
charset=ISO-8859-1;
delsp=yes;
format=flowed
This is the first part.
--Apple-Mail-13-196941151
Content-Type: message/rfc822
From xxxx@xxxx.com Tue May 10 11:28:07 2005
Return-Path: <xxxx@xxxx.com>
X-Original-To: xxxx@xxxx.com
Delivered-To: xxxx@xxxx.com
Received: from localhost (localhost [127.0.0.1])
by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F
for <xxxx@xxxx.com>; Tue, 10 May 2005 17:26:50 +0000 (GMT)
Received: from xxx.xxxxx.com ([127.0.0.1])
by localhost (xxx.xxxxx.com [127.0.0.1]) (amavisd-new, port 10024)
with LMTP id 70060-03 for <xxxx@xxxx.com>;
Tue, 10 May 2005 17:26:49 +0000 (GMT)
Received: from xxx.xxxxx.com (xxx.xxxxx.com [69.36.39.150])
by xxx.xxxxx.com (Postfix) with ESMTP id 8B957A94B
for <xxxx@xxxx.com>; Tue, 10 May 2005 17:26:48 +0000 (GMT)
Received: from xxx.xxxxx.com (xxx.xxxxx.com [64.233.184.203])
by xxx.xxxxx.com (Postfix) with ESMTP id 9972514824C
for <xxxx@xxxx.com>; Tue, 10 May 2005 12:26:40 -0500 (CDT)
Received: by xxx.xxxxx.com with SMTP id 68so1694448wri
for <xxxx@xxxx.com>; Tue, 10 May 2005 10:26:40 -0700 (PDT)
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;
s=beta; d=xxxxx.com;
h=received:message-id:date:from:reply-to:to:subject:mime-version:content-type;
b=g8ZO5ttS6GPEMAz9WxrRk9+9IXBUfQIYsZLL6T88+ECbsXqGIgfGtzJJFn6o9CE3/HMrrIGkN5AisxVFTGXWxWci5YA/7PTVWwPOhJff5BRYQDVNgRKqMl/SMttNrrRElsGJjnD1UyQ/5kQmcBxq2PuZI5Zc47u6CILcuoBcM+A=
Received: by 10.54.96.19 with SMTP id t19mr621017wrb;
Tue, 10 May 2005 10:26:39 -0700 (PDT)
Received: by 10.54.110.5 with HTTP; Tue, 10 May 2005 10:26:39 -0700 (PDT)
Message-ID: <xxxx@xxxx.com>
Date: Tue, 10 May 2005 11:26:39 -0600
From: Test Tester <xxxx@xxxx.com>
Reply-To: Test Tester <xxxx@xxxx.com>
To: xxxx@xxxx.com, xxxx@xxxx.com
Subject: Another PDF
Mime-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_Part_2192_32400445.1115745999735"
X-Virus-Scanned: amavisd-new at textdrive.com
------=_Part_2192_32400445.1115745999735
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
Just attaching another PDF, here, to see what the message looks like,
and to see if I can figure out what is going wrong here.
------=_Part_2192_32400445.1115745999735
Content-Type: application/pdf; name="broken.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="broken.pdf"
JVBERi0xLjQNCiXk9tzfDQoxIDAgb2JqDQo8PCAvTGVuZ3RoIDIgMCBSDQogICAvRmlsdGVyIC9G
bGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9Wt2KJbkNvm/od6jrhZxYln9hWEh2p+8HBvICySaE
ycLuTV4/1ifJ9qnq09NpSBimu76yLUuy/qzqcPz7+em3Ixx/CDc6CsXxs3b5+fvfjr/8cPz6/BRu
rbfAx/n3739/fuJylJ5u5fjX81OuDr4deK4Bz3z/aDP+8fz0yw8g0Ofq7ktr1Mn+u28rvhy/jVeD
QSa+9YNKHP/pxjvDNfVAx/m3MFz54FhvTbaseaxiDoN2LeMVMw+yA7RbHSCDzxZuaYB2E1Yay7QU
x89vz0+tyFDKMlAHK5yqLmnjF+c4RjEiQIUeKwblXMe+AsZjN1J5yGQL5DHpDHksurM81rF6PKab
gK6zAarIDzIiUY23rJsN9iorAE816aIu6lsgAdQFsuhhkHOUFgVjp2GjMqSewITXNQ27jrMeamkg
1rPI3iLWG2CIaSBB+V1245YVRICGbbpYKHc2USFDl6M09acQVQYhlwIrkBNLISvXhGlF1wi5FHCw
wxZkoGNJlVeJCEsqKA+3YAV5AMb6KkeaqEJQmFKKQU8T1pRi2ihE1Y4CDrqoYFFXYjJJOatsyzuI
8SIlykuxKTMibWK8H1PgEvqYgs4GmQSrEjJAalgGirIhik+p4ZQN9E3ETFPAHE1b8pp1l/0Rc1gl
fQs0ABWvyoZZzU8VnPXwVVcO9BEsyjEJaO6eBoZRyKGlrKoYoOygA8BGIzgwN3RQ15ouigG5idZQ
fx2U4Db2CqiLO0WHAZoylGiCAqhniNQjFjQPSkmjwfNTgQ6M1Ih+eWo36wFmjIxDJZiGUBiWsAyR
xX3EekGOizkGI96Ol9zVZTAivikURhRsHh2E3JhWMpSTZCnnonrLhMCodgrNcgo4uyJUJc6qnVss
nrGd1Ptr0YwisCOYyIbUwVjV4xBUNLbguSO2YHujonAMJkMdSI7bIw91Akq2AUlMUWGFTMAOamjU
OvZQCxIkY2pCpMFo/IwLdVLHs6nddwTRrgoVbvLU9eB0G4EMndV0TNoxHbt3JBWwK6hhv3iHfDtF
yokB302IpEBTnWICde4uYc/1khDbSIkQopO6lcqamGBu1OSE3N5IPSsZX00CkSHRiiyx6HQIShsS
HSVNswdVsaOUSAWq9aYhDtGDaoG5a3lBGkYt/lFlBFt1UqrYnzVtUpUQnLiZeouKgf1KhRBViRRk
ExepJCzTwEmFDalIRbLEGtw0gfpESOpIAF/NnpPzcVCG86s0g2DuSyd41uhNGbEgaSrWEXORErbw
------=_Part_2192_32400445.1115745999735--

--Apple-Mail-13-196941151--
28 changes: 18 additions & 10 deletions spec/mail/attachments_list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def check_decoded(actual, expected)
before(:each) do
@mail = Mail.new
end

describe "from direct content" do
it "should work" do
file_data = File.read(filename = fixture('attachments', 'test.png'))
Expand All @@ -39,17 +39,17 @@ def check_decoded(actual, expected)
@mail.attachments['test.png'] = File.read(fixture('attachments', 'test.png'))
@mail.attachments[0].filename.should == 'test.png'
end

end

describe "from a supplied Hash" do
it "should work" do
file_data = File.read(filename = fixture('attachments', 'test.png'))
@mail.attachments['test.png'] = { :content => file_data }
@mail.attachments[0].filename.should == 'test.png'
check_decoded(@mail.attachments[0].decoded, file_data)
end

it "should allow you to override the content_type" do
file_data = File.read(filename = fixture('attachments', 'test.png'))
@mail.attachments['test.png'] = { :content => file_data,
Expand All @@ -63,7 +63,7 @@ def check_decoded(actual, expected)
:mime_type => "application/x-gzip" }
@mail.attachments[0].mime_type.should == 'application/x-gzip'
end

it "should allow you to override the mime_type" do
file_data = File.read(filename = fixture('attachments', 'test.png'))
@mail.attachments['invoice.jpg'] = { :data => "you smiling",
Expand All @@ -75,7 +75,7 @@ def check_decoded(actual, expected)
end

describe "decoding and encoding" do

it "should set it's content_transfer_encoding" do
file_data = File.read(filename = fixture('attachments', 'test.png'))
@mail.attachments['test.png'] = { :content => file_data }
Expand Down Expand Up @@ -133,7 +133,7 @@ def check_decoded(actual, expected)
end

end

describe "setting the content type correctly" do
it "should set the content type to multipart/mixed if none given and you add an attachment" do
mail = Mail.new
Expand All @@ -147,7 +147,7 @@ def check_decoded(actual, expected)

describe "reading emails with attachments" do
describe "test emails" do

it "should find the attachment using content location" do
mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_content_location.eml')))
mail.attachments.length.should == 1
Expand All @@ -162,12 +162,12 @@ def check_decoded(actual, expected)
mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_content_disposition.eml')))
mail.attachments[0].filename.should == 'hello.rb'
end

it "should decode an attachment" do
mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_pdf.eml')))
mail.attachments[0].decoded.length.should == 1026
end

it "should find an attachment that has an encoded name value" do
mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_with_encoded_name.eml')))
mail.attachments.length.should == 1
Expand All @@ -180,5 +180,13 @@ def check_decoded(actual, expected)
result.should == expected
end

it "should find attachments inside parts with content-type message/rfc822" do
mail = Mail.read(fixture(File.join("emails",
"attachment_emails",
"attachment_message_rfc822.eml")))
mail.attachments.length.should == 1
mail.attachments[0].decoded.length.should == 1026
end

end
end

0 comments on commit 1e665e4

Please sign in to comment.