%%{
  # RFC 5322 Internet Message Format
  # https://tools.ietf.org/html/rfc5322
  #
  # RFC 6854 Update to Internet Message Format to Allow Group Syntax in the "From:" and "Sender:" Header Fields
  # https://tools.ietf.org/html/rfc6854
  machine rfc5322;
  alphtype int;

  include rfc5234_abnf_core_rules "rfc5234_abnf_core_rules.rl";

  # 3.2. Lexical Tokens
  include rfc5322_lexical_tokens "rfc5322_lexical_tokens.rl";

  # 3.3. Date and Time Specification
  include rfc5322_date_time "rfc5322_date_time.rl";

  # 3.4. Address Specification
  include rfc5322_address "rfc5322_address.rl";

  # 3.5. Overall Message Syntax
  #rfc5322_text = 0x01..0x09 | "\v" | "\f" | 0x0e..0x1f;
  #text = rfc5322_text | utf8_non_ascii; # RFC6532 for UTF-8
  #obs_body = ((LF* CR* ((0x00 | text) LF* CR*)*) | CRLF)*
  #body = ((text{,998} CRLF)* text{,998}) | obs_body;
  #message = (fields | obs_fields) (CRLF body)?;


  # 3.6. Field Definitions

  # 3.6.4. Identification Fields
  obs_id_left = local_part;
  obs_id_right = domain;
  no_fold_literal = "[" (dtext)* "]";

  msg_id_atext = rfc5322_atext | ":" | "," | "." | " ";

  id_left = msg_id_atext+ | obs_id_left;
  id_left_ns = ( msg_id_atext - ( " " | "," ) )+;

  # id_right modifications to support multiple '@' in msg_id.
  id_right = ( msg_id_atext | "@" )+ | no_fold_literal | obs_id_right;
  id_right_ns = ( msg_id_atext - ( " " | "," ) | "@" )+ | no_fold_literal;

  # Handle various message-id formats:
  #  <id_left@id_right>
  #  <id_left@id_right...
  #  <id_left@>
  #  <id_left>
  #  <id_left...
  #  id_left@id_right
  #  id_left
  # Handle comma-separated message_ids.
  msg_id = (CFWS)? (
      (("<" id_left "@" id_right? ">") >msg_id_s %msg_id_e) |
      (("<" id_left "@" id_right? :>> "...") >msg_id_s %msg_id_e) |
      (("<" id_left ">") >msg_id_s %msg_id_e) |
      (("<" id_left :>> "..." ) >msg_id_s %msg_id_e) |
      ((id_left_ns ("@" id_right_ns)? ) >msg_id_s %msg_id_e)
    ) (CFWS)? <: ","?;
  message_ids = msg_id**;


  # 3.6.7 Trace Fields
  # Added CFWS? to increase robustness (qmail likes to include a comment)
  received_token = word | angle_addr | addr_spec_no_angle_brackets | domain;
  received = ((CFWS? received_token*) >received_tokens_s %received_tokens_e)
              ";" date_time;

  # Envelope From
  ctime_date = day_name " "+ month " "+ day " " time_of_day " " year;
  null_sender = ('<>' ' '{0,1});
  envelope_from = (addr_spec_no_angle_brackets | null_sender) >address_s %address_e (" " (ctime_date >ctime_date_s %ctime_date_e))?;
}%%
