class GxG::Networking::SmtpClient

SMTP Classes:

Public Class Methods

new(host=nil,port=nil,options={}) click to toggle source
# File lib/gxg/net_clients.rb, line 1375
def initialize(host=nil,port=nil,options={})
  if port.is_a?(::Hash)
    options = port
    port = nil
  end
  @user = nil
  @password = nil
  @client = nil
  @host = host
  unless @host
    raise ArgumentError, "You MUST provide a HOST, like this: <host>,(<port>),(<options>)"
  end
  if options[:use_ssl] == true
    @port = (port || 465)
    if options[:ssl_method]
      # Valid: [:TLSv1, :TLSv1_server, :TLSv1_client, :TLSv1_1, :TLSv1_1_server, :TLSv1_1_client, :TLSv1_2, :TLSv1_2_server, :TLSv1_2_client, :SSLv23, :SSLv23_server, :SSLv23_client]
      unless OpenSSL::SSL::SSLContext::METHODS.include?(options[:ssl_method])
        raise ArgumentError, "Encryption method #{options[:ssl_method].inspect} is not valid. Choose one of these: #{OpenSSL::SSL::SSLContext::METHODS.inspect}"
      end
      openssl_context = OpenSSL::SSL::SSLContext.new(options[:ssl_method])
    else
      openssl_context = ::Net::SMTP.default_ssl_context
    end
    if options[:ignore_ssl_errors] == true
      openssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
    else
      openssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
    end
  else
    @port = (port || 25)
    openssl_context = nil
  end
  @client = ::Net::SMTP.new(@host, @port)
  if openssl_context
    @client.enable_ssl(openssl_context)
  end
  #
  self
end

Public Instance Methods

attachment_template(the_path="", content_parameters={"name" => ""}) click to toggle source
# File lib/gxg/net_clients.rb, line 1472
def attachment_template(the_path="", content_parameters={"name" => ""})
  result = nil
  begin
    unless the_path.to_s.valid_path?
      raise ArgumentError, "You MUST provide a valid file system path to the file."
    end
    unless content_parameters.is_a?(::Hash)
      raise ArgumentError, "You MUST provide content_parameters as a Hash."
    end
    unless content_parameters["name"].to_s.size > 0
      content_parameters["name"] = ::File.basename(the_path)
    end
    discovered_mime = ::MimeMagic.by_magic(::File.open(the_path,"rb"))
    if discovered_mime
      discovered_mime = discovered_mime.type
    else
      discovered_mime = "application/octet-stream"
    end
    result = {:content_type => {:type => discovered_mime, :parameters => content_parameters}, :filename => (::File.basename(the_path)), :path => the_path, :content => ::GxG::ByteArray.new}
  rescue Exception => the_error
    log_error({:error => the_error, :parameters => {:path => the_path, :content_parameters => content_parameters}})
  end
  result
end
host() click to toggle source
# File lib/gxg/net_clients.rb, line 1415
def host()
  @host.clone
end
login(user_id=nil,password=nil,authentication_method=:plain) click to toggle source
# File lib/gxg/net_clients.rb, line 1423
def login(user_id=nil,password=nil,authentication_method=:plain)
  result = false
  if @client
    begin
      @user = user_id
      unless @user
        raise ArgumentError, "You MUST provide a USER id, like this: <user_id>,<password/oauth-token>,(<options>)"
      end
      @password = password
      unless @password
        raise ArgumentError, "You MUST provide a PASSWORD/OAUTH-TOKEN, like this: <user_id>,<password/oauth-token>,(<options>)"
      end
      unless @client.started?
        unless [:plain, :login, :cram_md5, :oauth2].include?(authentication_method.to_s.to_sym)
          raise ArgumentError, "Authentication method #{authentication_method.inspect} is invalid. Choose one of these: [:plain, :login, :cram_md5, :oauth2]"
        end
        # Internal cosmetics for interface consistency.
        if authentication_method == :oauth2
          authentication_method = :xoauth2
        end
        @client.start(@host, @user, @password, authentication_method)
      end
      result = true
    rescue Exception => the_error
      # Internal cosmetics for interface consistency.
      if authentication_method == :xoauth2
        authentication_method = :oauth2
      end
      log_error({:error => the_error, :parameters => {:user => user_id, :authentication => authentication_method}})
    end
  end
  result
end
logout() click to toggle source
# File lib/gxg/net_clients.rb, line 1457
def logout()
  if @client
    begin
      @client.finish
      @client = nil
      true
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {}})
      false
    end
  else
    false
  end
end
message_template(mime_type="text/plain", content_parameters={"charset"=>"UTF-8"}) click to toggle source
# File lib/gxg/net_clients.rb, line 1497
def message_template(mime_type="text/plain", content_parameters={"charset"=>"UTF-8"})
  result = nil
  begin
    unless ['text/plain', 'text/html', 'text/xhtml', 'text/xml'].include?(mime_type.to_s)
      raise ArgumentError, "Content Type specified was invalid. Choose one of these: ['text/plain', 'text/html', 'text/xhtml', 'text/xml']"
    end
    unless content_parameters.is_a?(::Hash)
      raise ArgumentError, "You MUST provide content_parameters as a Hash."
    end
    gxg_message = new_message
    gxg_message[:sender] = ""
    gxg_message[:id] = "<#{gxg_message[:id].to_s}@#{::Socket.gethostname}.mail>"
    gxg_message[:to] = ""
    gxg_message[:cc] = nil
    gxg_message[:bcc] = nil
    gxg_message[:subject] = ""
    gxg_message[:date] = ::DateTime.now
    gxg_message[:header] = {}
    gxg_message[:body] = [{:prologue => ""},{:content_type => {:type => mime_type.to_s, :parameters => content_parameters}, :content => ""},{:epilogue => ""}]
    gxg_message[:attachments] = []
    result = gxg_message
  rescue Exception => the_error
    log_error({:error => the_error, :parameters => {:content_type => mime_type, :content_parameters => content_parameters}})
  end
  result
end
port() click to toggle source
# File lib/gxg/net_clients.rb, line 1419
def port()
  @port.clone
end
send_message(gxg_message=nil) click to toggle source
# File lib/gxg/net_clients.rb, line 1524
def send_message(gxg_message=nil)
  result = false
  if @client
    begin
      unless @client.started?
        raise Exception, "SMTP session not started yet."
      end
      unless gxg_message.is_a?(::GxG::Events::Message)
        raise ArgumentError, "You MUST provide a valid message object of class ::GxG::Events::Message. Suggested: <SmtpClient>.message_template(<Mime-Type-String>)"
      end
      # Build suitable mail message
      message = Mail.new
      the_fields = []
      gxg_message[:header].each_pair do |the_key, the_value|
        if the_value.is_a?(::Array)
          the_value.each do |the_field_value|
            the_fields << "#{the_key.to_s}: #{the_field_value.to_s}"
          end
        else
          the_fields << "#{the_key.to_s}: #{the_value.to_s}"
        end
      end
      message.header = the_fields.join("\r\n")
      message.from = gxg_message[:sender]
      message.reply_to = gxg_message[:sender]
      if gxg_message[:id].to_s.include?("@")
        message.message_id = gxg_message[:id].to_s
      else
        message.message_id = "<#{gxg_message[:id].to_s}@#{::Socket.gethostname}.mail>"
      end
      message.to = gxg_message[:to]
      if gxg_message[:cc]
        message.cc = gxg_message[:cc]
      end
      if gxg_message[:bcc]
        message.bcc = gxg_message[:bcc]
      end
      message.subject = gxg_message[:subject]
      message.date = (gxg_message[:date].to_s || ::DateTime.now.to_s)
      if gxg_message[:attachments].size > 0
        multipart = true
      else
        part_count = 0
        gxg_message[:body].each do |part|
          unless part[:prologue] || part[:epilogue]
            part_count += 1
          end
        end
        if part_count > 1
          multipart = true
        else
          multipart = false
        end
      end
      if multipart
        gxg_message[:body].each do |part|
          unless part[:prologue] || part[:epilogue]
            type_info = "Content-Type: #{part[:content_type][:type]}"
            if part[:content_type][:parameters].keys.size > 0
              part[:content_type][:parameters].each_pair do |the_key, the_value|
                type_info << "; '#{the_key.to_s}': '#{the_value.to_s}'"
              end
            end
            new_part = Mail::Part.new(type_info)
            new_part.body = part[:content]
            message.add_part(new_part)
          end
        end
        # Add file attachments:
        gxg_message[:attachments].each do |attachment|
          if attachment[:content].size == 0
            file_size = ::File.size(attachment[:path])
            file_handle = ::File.open(attachment[:path],"rb")
            ::GxG::apportioned_ranges(file_size,65536).each do |the_range|
              file_handle.seek(the_range.first)
              attachment[:content] << file_handle.read(the_range.size)
            end
            file_handle.close
          end
          message.add_file({:filename => attachment[:filename], :content => attachment[:content].to_s})
        end
      else
        gxg_message[:body].each do |part|
          unless part[:prologue] || part[:epilogue]
            message.body = part[:content]
            break
          end
        end
      end
      # Send it
      @client.send_message(message.to_s, gxg_message[:sender], message.destinations) 
    rescue Exception => the_error
      log_error({:error => the_error, :parameters => {:message => gxg_message}})
    end
  end
  result
end