class Buryspam::Forward

Class to send mail to a forwarding address as it is pulled over from an IMAP server. (We may want to nest this class in the MUN_IMAP module in the future.)

Constants

DFLT_SMTP_PORT

Attributes

prevent[W]

Messages sent to folders that match the fwd_inhibit configuration parameter are not forwarded.

Public Class Methods

new(to_addr) click to toggle source

Create a new forwarding object based upon the given destination address. Get and store the mx records for the forwarded address's domain in preparation for calling the send method.

# File buryspam.rb, line 744
def initialize(to_addr)
  @to_addr = to_addr.strip
  @from_addr = Config.fwd_from || ""
  @prevent = false

  # The stuff after the last "@" is the domain.
  domain = @to_addr[/.*@(.*)/, 1]
  if domain.nil?
    raise ArgumentError, "Forwarding address: <#{@to_addr}> missing '@'"
  end

  @mx_servers = get_mx_servers(domain)

  @fwd_smtp_server = Config.fwd_smtp_server || ""
  @fwd_smtp_port   = Config.fwd_smtp_port || DFLT_SMTP_PORT

  if @fwd_smtp_server.strip.empty?
    Logger.debug("No forwarding SMTP server given.")
  else
    # If supplied, we'll use the user supplied SMTP server/port as
    # a last resort when forwarding the message.
    Logger.debug("Added %s:%s to list of mail servers" %
                 [@fwd_smtp_server, @fwd_smtp_port])
    @mx_servers << [@fwd_smtp_server, @fwd_smtp_port]
  end

  # Fully qualified domain name of the local host.  Used for the
  # HELO SMTP command.
  @helo_fqdn = Socket.gethostbyname(Startup::HOSTNAME).first
end

Public Instance Methods

send(msg) click to toggle source

Forward the given IMAP message to the destination specified by the forward-related configuration parameters.

# File buryspam.rb, line 777
def send(msg)
  if @prevent
    Logger.info("Message not forwarded.")
    return
  end
  servers = @mx_servers.dup

  server = servers.shift
  msg = msg.attr["RFC822"].sub(/\AReturn-Path:.*\r?\n/, "")
  begin
    # default port for all mx servers determined earlier.
    port = DFLT_SMTP_PORT

    # User specified SMTP server/port.
    if server.class == Array
      server, port = server
    end
    Logger.info("Connecting to #{server}...")
    Net::SMTP.start(server, port, @helo_fqdn) do |smtp|
      smtp.sendmail(msg, @from_addr, @to_addr)
    end
  rescue Exception => ex
    Logger.warn("Cannot forward to #{@to_addr} via #{server}: #{ex.message}")
    if servers.empty?
      raise "Exhausted all servers during forwarding.  Giving up."
    end
    server = servers.shift
    retry
  end
  Logger.info("Message forwarded.")
end

Private Instance Methods

get_mx_servers(domain) click to toggle source

Return an array of the mx server names for the given domain in order of preference.

# File buryspam.rb, line 812
def get_mx_servers(domain)
  dns = Resolv::DNS.new
  mx = dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
  mx = mx.collect {|r| [r.preference, r.exchange.to_s] }.sort
  records = mx.map { |rec| "\t#{rec[1]} (pref: #{rec[0]})" }
  Logger.debug("MX Records for '#{domain}':\n" + records.join("\n"))
  mx.collect{ |rec| rec[1] }
end