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