From: Shashank Date Date: 2003-09-02T08:29:39+09:00 Subject: Email with attachments? 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