I have searched RAA and ruby-talk (esp. [40428]) and I have
still not managed to find a simple solution to “sending email with
binary attachments” on Windows. The code given in ruby-talk
[40429] is badly mangled and I tried resurrecting it , but am not
sure about lines 37 thru 57 (if they do not get further mangled).
I get the following error:
error on sending: The remote adapter is not compatible - connect(2)
Also, does the ability to “create MIME e-mail” automatically
imply attachment functionality ? If yes, then I guess I need to
figure it out with Tmail and RubyMail.
Any suggestions?
TIA,
– shanko
---------------------- line 0 --------------------------------
File: CyOSendMimeMailSmtp.rb
Author: Oliver Mensinger
Version: 2002-01-22
Status: Usable and stable
(for simple mails incl. binary attachm.)
···
Description:
Create Mime mail with text and attachments and
send it via SMTP
Changes:
2002-01-22 After Ian reported a problem, the mail
server address is now given to Net::SMTP::new
instead to Net:SMTP::start
Supported functions: text part, binary attachments
read from file
To do: html part, binary attachment given to method
as parameter, several recipients(cc, bcc)
require "net/smtp"
require “getoptlong”
class CyOSendMimeMailSmtp
attr_accessor :text, :server,:from,:to,:subject
def initialize()
@boundary = createBoundary()
# attachments are stored in an array,
# each index is an hash see attach method
@attachments = []
@serverlocalhost = “”
@subject = “no subject”
@from = @to = @text = ""
end
---------------- line 37 -------------
def createBoundary()
return ["----=CyOSendMimeMailSmtp_Part"] +
uniqueNumber()
end
private :createBoundary
create an unique number, length variables
def uniqueNumber()
return [
sprintf("%02X", rand(999999990000000)), # random part
sprintf("%02X", Time.new.to_i), # machine time
sprintf("%02X", $_), # process
number
sprintf("%02X", Time.new.usec()) # micro seconds of machine
]
end
private :uniqueNumber
---------------- line 57 -------------
attachBinaryFile(phy_filename, real_filename)
adds a file and converts it to base64
phy_filename is the physical filenameincl. path) of a file that must
exist
real_filename will be the name of the file in the mail message
if real_filename is not given, it will be the physical filename
returns true if file exists and was attached to mail, otherwise false
def attachBinaryFile(phy_filename, real_filename)
# read file into string and convert it to base64
begin
f = File.new(phy_filename);
data = f.read()
f.close()
rescue
return false
end
data = [data].pack("m*");
real_filename = phy_filename if (real_filename=="")
# the very special problem of phy_filename and real_filename:
# the physical filename could be something like
# tmp/12367672647342342,
# as an external binary file stored outside of a database, where the
# real filename is the original filename which is stored in the database
# so we take the real_filename for determining the files type
attachment = {"type" => contentType(real_filename),
"name" => File.basename(real_filename),
"data" => data }
@attachments.push(attachment)
end
def contentType(filename)
filename = File.basename(filename).downcase
return “image/jpg” if (filename =~ /.jp(e?)g$/)
return “image/gif” if (filename =~ /.gif$/)
return “text/html” if (filename =~ /.htm(l?)$/)
return “text/plain” if (filename =~ /.txt$/ )
return “application/zip” if (filename =~ /.zip$/)
# more types?!
return "application/octet-stream"
end
private :contentType
def sendMail()
raise "mail server not specified" if(@server.length == 0)
raise "sender address not specified" if(@from.length == 0)
raise "receiver address not specified" if(@to.length == 0)
#raise "nothing to send" if((@text.length==0)&(@attachments.length==0))
smtp = Net::SMTP.new(@server)
smtp.start()
smtp.ready(@from, @to) do |wa|
wa.write("Reply-To:{@from}\r\n")
wa.write("To:{@to}\r\n")
wa.write("Subject:{@subject}\r\n")
wa.write("MIME-Version:.0\r\n")
# add multipart header if we have got attachments
if(@attachments.length)
wa.write("Content-Type: multipart/mixed;
boundary="#{@boundary}"\r\n")
wa.write("\r\n")
wa.write(“This is a multi-part message in MIME format.\r\n”)
wa.write("\r\n")
end
# add text part if given
if(@text.length)
# add boundary if we are multiparted, otherwise just add text
if(@attachments.length)
wa.write("--#{@boundary}\r\n")
wa.write("Content-Type: text/plain; charset=\"iso-8859-1\"\r\n")
wa.write("Content-Transfer-Encoding:bit\r\n")
# we don't take care of very old mail servers with bit only
else
# if only text and no attachm. we give the encoding
wa.write("Content-Type: text/plain; charset=iso-8859-1\r\n")
wa.write("Content-Transfer-Encoding:bit\r\n")
end
wa.write("\r\n")
wa.write("#{@text}\r\n")
wa.write("\r\n")
end
# add attachments if given
if(@attachments.length)
@attachments.each do |part|
wa.write("--#{@boundary}\r\n")
wa.write("Content-Type:{part['type']};
name="#{part[‘name’]}"\r\n")
wa.write(“Content-Transfer-Encoding: base64\r\n”)
wa.write(“Content-Disposition: attachment;
filename=”#{part[‘name’]}"\r\n")
wa.write("\r\n")
wa.write("#{part[‘data’]}") # no more need for \r\n here!
wa.write("\r\n")
end
end
# closing boundary if multiparted
wa.write("--#{@boundary}--\r\n") if(@attachments.length)
end # smtp.ready(...)
end # def sendMail()
end # class CyOSendMimeMailSmtp
if $0 == FILE
example for using CyOSendMimeMailSmtp class
require “CyOSendMimeMailSmtp.rb”
mail = CyOSendMimeMailSmtp.new()
mail.server = "pop3.everestkc.net"
mail.from = "sdate@everestkc.net"
mail.to = "shanko_date@yahoo.com"
mail.subject = "1st test using class CyOSendMimeMailSmtp"
mail.text = “I love Ruby!\n2nd line.”
#if(!mail.attachBinaryFile("/home/cyo/ruby.jpg"))
puts “could not attach file”
#end
begin
mail.sendMail()
rescue
puts "error on sending: #{$!}"
end
end