module Sisimai::MDA

Sisimai::MDA - Error message parser for MDA

Constants

AgentNames
MarkingsOf
MessagesOf

dovecot/src/deliver/mail-send.c:94

Public Class Methods

make(mhead, mbody) click to toggle source

Parse message body and return reason and text @param [Hash] mhead Message headers of a bounce email @param [String] mbody Message body of a bounce email @return [Hash] Bounce data list and message/rfc822 part @return [Nil] it failed to parse or the arguments are missing

# File lib/sisimai/mda.rb, line 82
def make(mhead, mbody)
  return nil unless mhead['from'].downcase.start_with?('mail delivery subsystem','mailer-daemon', 'postmaster')

  agentname0 = ''   # [String] MDA name
  reasonname = ''   # [String] Error reason
  bouncemesg = ''   # [String] Error message
  bodyslices = mbody.split("\n")
  linebuffer = []

  while e = bodyslices.shift do
    # Check each line with each MDA's symbol regular expression.
    if agentname0 == ''
      # Try to match with each regular expression
      next if e.empty?
      next unless e =~ MarkingsOf[:message]

      AgentNames.each_key do |f|
        # Detect the agent name from the line
        next unless e =~ AgentNames[f]
        agentname0 = f
        break
      end
    end

    # Append error message lines to @linebuffer
    linebuffer << e
    break if e.empty?
  end
  return nil if agentname0.empty?
  return nil if linebuffer.empty?

  MessagesOf[agentname0].each_key do |e|
    # Detect an error reason from message patterns of the MDA.
    duplicated = linebuffer.dup
    while f = duplicated.shift do
      # Whether the error message include each message defined in $MessagesOf
      next unless MessagesOf[agentname0][e].any? { |a| f.downcase.include?(a) }
      reasonname = e
      bouncemesg = f
      break
    end
    break if bouncemesg.size > 0 && reasonname.size > 0
  end

  return {
    'mda'     => agentname0,
    'reason'  => reasonname || '',
    'message' => bouncemesg || '',
  }
end