Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Retrieve email attachments using Net::IMAP

627 views
Skip to first unread message

luke

unread,
May 31, 2006, 4:21:00 AM5/31/06
to
Hi,

I'm trying to write a Ruby script that will connect to my mail server
using IMAP, check for new email, and if an email has an attachment then
it will save the attachment into a certain local directory. And that's
it! I don't actually care about the contents of the email. This will be
simply a way of collecting files that are sent as attachments to a
certain email address.

I've been looking around for 2 nights and so far haven't been able to
find something myself that demonstrates how to retrieve attachments
using the Net::IMAP library, or using something that works into that
library.

I have my code to the point where it connects successfully to my mail
server, and then prints some subject lines just to say email is being
detected. I've tried googling, checking script libraries and reading
through the API docs for the standard library to no avail. Can someone
give me some pointers?

Thanks
Luke

luked

unread,
Jun 1, 2006, 6:03:53 AM6/1/06
to
OK, I've made a bit of progress on this issue, but still I can't locate
where the binary file is, or work out how to initiate a transfer of it
to another local directory.

What I've got so far is below:

require 'net/imap'

imap = Net::IMAP.new('domain.name.com')
imap.authenticate('LOGIN', 'mailbox', 'password')
imap.select('INBOX')
imap.search(["SINCE", "8-Aug-2002"]).each do |message_id|
attach = imap.fetch(message_id, "BODY")[0].attr["BODY"]
puts "#{attach.parts[1].media_type}"
puts "#{attach.parts[1].param['NAME']}"
puts "#{attach.parts[1].subtype}"
puts "#{(attach.parts[1].size)/1024} kb"
end


It simply prints out information about the attachment, like this:

IMAGE
filename.jpg
JPEG
35 kb


I hope this isn't a really basic question, but what is the next step to
saving this file attachment?

Thanks
Luke

Dave Burt

unread,
Jun 1, 2006, 6:26:08 AM6/1/06
to
luked wrote:
> OK, I've made a bit of progress on this issue, but still I can't locate
> where the binary file is, or work out how to initiate a transfer of it
> to another local directory.
>
> What I've got so far is below:
>
> require 'net/imap'
>
> imap = Net::IMAP.new('domain.name.com')
> imap.authenticate('LOGIN', 'mailbox', 'password')
> imap.select('INBOX')
> imap.search(["SINCE", "8-Aug-2002"]).each do |message_id|
> attach = imap.fetch(message_id, "BODY")[0].attr["BODY"]
> puts "#{attach.parts[1].media_type}"
> puts "#{attach.parts[1].param['NAME']}"
> puts "#{attach.parts[1].subtype}"
> puts "#{(attach.parts[1].size)/1024} kb"
> end
>
>
> It simply prints out information about the attachment, like this:
>
> IMAGE
> filename.jpg
> JPEG
> 35 kb
>
>
> I hope this isn't a really basic question, but what is the next step to
> saving this file attachment?

You should be hoping it _is_ a really basic question; that way someone
will be able to help you!

I have two pieces of advice. The first is trivial and won't help you
much: 'puts "#{foo}"' is the same as 'puts foo', so you should use the
latter for at least three of those four debug-print lines.

Secondly, you can find out what kind of object parts[1] is by printing
parts[1].class and what interesting methods it has by p'ing (it's an
array) parts[1].class.instance_methods(false).sort or (parts[1].methods
- Object.instance_methods).sort.

HTH
Dave

ts

unread,
Jun 1, 2006, 7:02:32 AM6/1/06
to
>>>>> "l" == luked <ldun...@gmail.com> writes:


Try this

l> require 'net/imap'

l> imap = Net::IMAP.new('domain.name.com')
l> imap.authenticate('LOGIN', 'mailbox', 'password')
l> imap.select('INBOX')
l> imap.search(["SINCE", "8-Aug-2002"]).each do |message_id|
l> attach = imap.fetch(message_id, "BODY")[0].attr["BODY"]
l> puts "#{attach.parts[1].media_type}"
l> puts "#{attach.parts[1].param['NAME']}"
l> puts "#{attach.parts[1].subtype}"
l> puts "#{(attach.parts[1].size)/1024} kb"

puts imap.fetch(message_id, "BODY[2]")

l> end

it will give you a Net::IMAP::FetchData object


--

Guy Decoux

luked

unread,
Jun 2, 2006, 12:10:19 AM6/2/06
to

Thanks, that's helped another step!

It's returning an Array with 1 element. When I print the array to
screen I get a whole lot of ASCII characters, and when I save the
contents of the Array to a file it creates a file that equals the file
size of the attachment.

The problem though is that this file that I'm saving is not a
recognisable jpg. It won't open when I try to view it, so I imagine
that I haven't copied the binary.

When I open the file in a text editor I see 1 line of characters that
starts with

#<struct Net::IMAP::FetchData seqno=1,
attr={"BODY[2]"=>"/9j/4AAQSkZJRgABAQAAAQABAAD/2w

So it looks like I've just saved information about the array rather
than the contents.

Luke

Clifford Heath

unread,
Jun 2, 2006, 12:32:32 AM6/2/06
to
luked wrote:
> Thanks, that's helped another step!
> It's returning an Array with 1 element.
> #<struct Net::IMAP::FetchData seqno=1,
> attr={"BODY[2]"=>"/9j/4AAQSkZJRgABAQAAAQABAAD/2w
>
> So it looks like I've just saved information about the array rather
> than the contents.

That looks like base64 encoding. Did you check to see whether
the MIME headers mentioned a Content-Transfer-Encoding or a
Content-Encoding? You'll need to apply the reverse encoding
to get back your attachment.

Clifford Heath.

ts

unread,
Jun 2, 2006, 6:53:53 AM6/2/06
to
>>>>> "l" == luked <ldun...@gmail.com> writes:

l> The problem though is that this file that I'm saving is not a
l> recognisable jpg. It won't open when I try to view it, so I imagine
l> that I haven't copied the binary.

It's in base64 : you must decode it


--

Guy Decoux

0 new messages