Reputation: 2492
I've been trying to figure out how to send an e-mail to my gmail account with a binary attachment using the standard net/smtp. So far, I've succeeded in attaching a text file successfully - the following (based on what others have done) works for this:
#!/usr/bin/env ruby
require 'net/smtp'
addressee = '[email protected]'
server = 'smtp.gmail.com'
port = 587
account = 'ACCOUNT'
from = addressee
name = 'NAME'
domain = 'gmail.com'
subject = 'test of smtp using ruby'
body = 'Test of SMTP using Ruby.'
marker = "PART_SEPARATOR"
filename = "test-attachment"
filetext = "attachment contents"
print "Enter password for #{account}: "
password = $stdin.gets.chomp
# Define the main headers.
part1 = <<EOF
From: #{name} <#{from}>
To: <#{addressee}>
Subject: #{subject}
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=#{marker}
--#{marker}
EOF
# Define the message action
part2 = <<EOF
Content-Type: text/plain
Content-Transfer-Encoding:8bit
#{body}
--#{marker}
EOF
# Define the attachment section
part3 = <<EOF
Content-Type: text/plain
Content-Disposition: attachment; filename="#{File.basename(filename)}"
#{filetext}
--#{marker}--
EOF
message = part1 + part2 + part3
puts message
smtp = Net::SMTP.new server, port
smtp.enable_starttls
smtp.start(domain, account, password, :login) do
smtp.send_message message, from, addressee
end
The problem is replacing a text attachment with an encoded binary attachment. The following variation of the above looks like it should work based on what I've been able to google, but does not send the attachment correctly:
#!/usr/bin/env ruby
require 'net/smtp'
addressee = '[email protected]'
server = 'smtp.gmail.com'
port = 587
account = 'ACCOUNT'
from = addressee
name = 'NAME'
domain = 'gmail.com'
subject = 'test of smtp using ruby'
body = 'Test of SMTP using Ruby.'
marker = "PART_SEPARATOR"
filename = "test-attachment"
filetext = "attachment contents"
print "Enter password for #{account}: "
password = $stdin.gets.chomp
# Encode contents into base64 format
encodedcontent = [filetext].pack("m")
# Define the main headers.
part1 = <<EOF
From: #{name} <#{from}>
To: <#{addressee}>
Subject: #{subject}
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=#{marker}
--#{marker}
EOF
# Define the message action
part2 = <<EOF
Content-Type: text/plain
Content-Transfer-Encoding:8bit
#{body}
--#{marker}
EOF
# Define the attachment section
part3 = <<EOF
Content-Type: multipart/mixed; name="#{File.basename(filename)}"
Content-Transfer-Encoding:base64
Content-Disposition: attachment; filename="#{File.basename(filename)}"
#{encodedcontent}
--#{marker}--
EOF
message = part1 + part2 + part3
puts message
smtp = Net::SMTP.new server, port
smtp.enable_starttls
smtp.start(domain, account, password, :login) do
smtp.send_message message, from, addressee
end
Can anyone tell me what I'm doing wrong?
Upvotes: 4
Views: 1493
Reputation: 2492
I've finally managed to send a binary attachment - the secret was using
Content-Type: application/octet-stream; name="#{filename}"
Content-Disposition: attachment; filename="#{filename}"; size=#{size}
in the attachment portion (part 3) of the message.
One other thing, this worked fine for a small test attachment, but when I tried a larger (140K) attachment, the attachment was truncated. Using
filecontent = File.binread(pathname)
rather than
filecontent = File.read(pathname)
seems to solve the problem. (I'm not quite sure why.)
Upvotes: 1