Retrieve email attachments using Net::IMAP

L

luke

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
 
L

luked

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
 
D

Dave Burt

luked said:
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
 
T

ts

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
 
L

luked

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

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
 
C

Clifford Heath

luked said:
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.
 
T

ts

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top