跳到主要内容

3. 语法

3.1. 引言

本节给出的语法定义了 Internet 消息的合法语法. 符合本规范的消息必须符合本节语法. 如果本节中的某些选项要求生成其中一个应该选项, 该要求会在正文中说明, 或在语法旁的注释中说明.

对于已定义的表达式, 本文先给出语法及其用途的简短说明, 随后给出 ABNF, 最后进行语义分析. 本文档使用但未另行规定的原始令牌取自 RFC 5234 附录 B.1 的 "Core Rules": CR, LF, CRLF, HTAB, SP, WSP, DQUOTE, DIGIT, ALPHA 和 VCHAR.

在某些定义中, 会出现名称以 "obs-" 开头的非终结符. 这些 "obs-" 元素指第 4 节过时语法中定义的令牌. 在所有情况下, 为生成合法 Internet 消息, 都应忽略这些产生式, 并且不得将它们用作此类消息的一部分. 但是, 在解释消息时, 这些令牌必须作为合法语法的一部分得到支持. 从这个意义上说, 第 3 节定义了用于生成消息的文法, 其中 "obs-" 元素应被忽略; 第 4 节则向该文法添加内容, 用于规定解释消息时使用的文法.

核心概念:

概念描述
消息生成使用第 3 节语法, 忽略 obs- 元素
消息解析使用第 3 节 + 第 4 节, 包含 obs- 元素
obs- 元素过时语法, MUST NOT 生成但 MUST 解析

3.2. 词法令牌

以下规则用于定义底层词法分析器, 该分析器向更高层解析器提供令牌. 本节定义结构化头部字段体中使用的令牌.

: 本规范读者需要特别注意这些词法令牌在文档后续的低层和高层语法中如何使用. 特别是, 第 3.2.2 节中定义的空白和注释令牌用于此处定义的低层令牌, 而这些低层令牌又作为后续定义的高层令牌的组成部分. 因此, 即使空白和注释没有显式出现在某个特定定义中, 它们也可能允许出现在更高层结构的令牌之间.

3.2.1. 引用字符

某些字符保留用于特殊解释, 例如用于分隔词法令牌. 为了允许这些字符作为未解释数据使用, 本规范提供一种引用机制.

quoted-pair     =   ("\" (VCHAR / WSP)) / obs-qp

任何出现 quoted-pair 的地方, 都应将其解释为去掉反斜杠后得到的单个字符. 也就是说, 作为 quoted-pair 一部分出现的 "" 字符在语义上是"不可见"的.

: "" 字符可能出现在消息中, 但并不是 quoted-pair 的一部分. 不在 quoted-pair 中出现的 "" 字符在语义上并非不可见. 本规范当前仅在 ccontent, qcontent 以及第 4 节的 obs-dtext 中使用 quoted-pair.

示例:

引用反斜杠: "\\"  → 解释为: \
引用引号: "\"" → 解释为: "
引用空格: "\ " → 解释为: (space)

3.2.2. 折叠空白和注释

空白字符, 包括用于折叠的空白字符 (见第 2.2.3 节), 可以出现在头部字段体中的许多元素之间. 此外, 被视为注释的字符串可以包含在结构化字段体中, 其形式是括在圆括号内的字符. 以下规则定义 folding white space (FWS, 折叠空白) 和注释结构.

括在圆括号中的字符串被视为注释, 前提是它们不出现在第 3.2.4 节定义的 "quoted-string" 中. 注释可以嵌套.

本规范中有若干位置允许自由插入注释和 FWS. 为适应该语法, 本规范为可出现注释和/或 FWS 的位置额外定义了 "CFWS" 令牌. 但是, 当本规范出现 CFWS 时, 不得以使任何折叠头部字段的某一行完全由 WSP 字符组成且没有其他内容的方式插入它.

FWS             =   ([*WSP CRLF] 1*WSP) /  obs-FWS
; Folding white space

ctext = %d33-39 / ; Printable US-ASCII
%d42-91 / ; characters not including
%d93-126 / ; "(", ")", or "\"
obs-ctext

ccontent = ctext / quoted-pair / comment

comment = "(" *([FWS] ccontent) [FWS] ")"

CFWS = (1*([FWS] comment) [FWS]) / FWS

在本规范中, 凡出现 FWS (折叠空白令牌) 的地方, 都表示可以进行第 2.2.3 节讨论的折叠. 消息中凡出现折叠 (即头部字段体包含 CRLF 后跟任意 WSP), 在对该头部字段执行进一步语义分析之前, 都要先展开 (移除 CRLF). 也就是说, FWS 中出现的任何 CRLF 在语义上都是"不可见"的.

注释示例:

From: Pete (A nice \) chap) ``<[email protected]>``
↑ ↑
└── 注释开始 └── 转义的圆括号

解析出的显示名: Pete
实际邮箱: [email protected]

3.2.3. 原子

结构化头部字段体中的若干产生式只是由某些基本字符组成的字符串. 这些产生式称为 atom (原子).

某些结构化头部字段体还允许句点字符 (".", ASCII 值 46) 出现在连续的 atext 字符中. 为此额外定义了 "dot-atom" 令牌.

atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
"!" / "#" / ; characters not including
"$" / "%" / ; specials. Used for atoms.
"&" / "'" /
"*" / "+" /
"-" / "/" /
"=" / "?" /
"^" / "_" /
"`" / "{" /
"|" / "}" /
"~"

atom = [CFWS] 1*atext [CFWS]

dot-atom-text = 1*atext *("." 1*atext)

dot-atom = [CFWS] dot-atom-text [CFWS]

specials = "(" / ")" / ; Special characters that do
"<" / ">" / ; not appear in atext
"[" / "]" /
":" / ";" /
"@" / "\" /
"," / "." /
DQUOTE

atom 和 dot-atom 都解释为单个单元, 由构成它们的字符字符串组成. 在语义上, 包围其余字符的可选注释和 FWS 不是 atom 的一部分; atom 仅是 atom 中连续的 atext 字符, dot-atom 则仅是 atext 和 "." 字符.

示例:

Atom 示例:
- john
- example
- user_name
- info+tag

Dot-atom 示例:
- john.doe
- first.middle.last
- [email protected] (for mailbox local part)

3.2.4. 引用字符串

包含 atom 中不允许出现的字符的字符串, 可以用 quoted-string (引用字符串) 格式表示, 即用 quote (DQUOTE, ASCII 值 34) 字符包围这些字符.

qtext           =   %d33 /             ; Printable US-ASCII
%d35-91 / ; characters not including
%d93-126 / ; "\" or the quote character
obs-qtext

qcontent = qtext / quoted-pair

quoted-string = [CFWS]
DQUOTE *([FWS] qcontent) [FWS] DQUOTE
[CFWS]

quoted-string 被视为一个单元. 也就是说, quoted-string 在语义上等同于 atom. 由于 quoted-string 可以包含 FWS, 因而允许折叠. 还要注意, 由于 quoted-pair 允许出现在 quoted-string 中, 引号和反斜杠字符只要以 quoted-pair 形式出现, 就可以出现在 quoted-string 中.

示例:

"Joe Q. Public"           → Joe Q. Public
"First Last" → First Last
"Giant; \"Big\" Box" → Giant; "Big" Box

3.2.5. 其他令牌

另外定义三个令牌: word 和 phrase 用于 atom 和/或 quoted-string 的组合, unstructured 用于非结构化头部字段, 以及结构化头部字段中的某些位置.

word            =   atom / quoted-string

phrase = 1*word / obs-phrase

unstructured = (*([FWS] VCHAR) *WSP) / obs-unstruct

3.3. 日期和时间规范

日期和时间值出现在若干头部字段中. 本节规定完整日期和时间规范的语法. 尽管整个 date-time 规范中允许折叠空白, 但推荐在每个出现 FWS 的位置 (无论必需还是可选) 使用单个空格; 某些较旧实现无法正确解释较长的折叠空白序列.

date-time       =   [ day-of-week "," ] date time [CFWS]

day-of-week = ([FWS] day-name) / obs-day-of-week

day-name = "Mon" / "Tue" / "Wed" / "Thu" /
"Fri" / "Sat" / "Sun"

date = day month year

day = ([FWS] 1*2DIGIT FWS) / obs-day

month = "Jan" / "Feb" / "Mar" / "Apr" /
"May" / "Jun" / "Jul" / "Aug" /
"Sep" / "Oct" / "Nov" / "Dec"

year = (FWS 4*DIGIT FWS) / obs-year

time = time-of-day zone

time-of-day = hour ":" minute [ ":" second ]

hour = 2DIGIT / obs-hour

minute = 2DIGIT / obs-minute

second = 2DIGIT / obs-second

zone = (FWS ( "+" / "-" ) 4DIGIT) / obs-zone

日期时间示例:

完整格式:
Date: Fri, 21 Nov 1997 09:55:06 -0600
Date: Mon, 20 Dec 2025 10:00:00 +0800

不含星期:
Date: 21 Nov 1997 09:55:06 -0600

UTC 时间:
Date: 21 Nov 1997 15:55:06 +0000

3.4. 地址规范

地址出现在若干消息头部字段中, 用于指明消息的发送者和接收者. 地址可以是单个 mailbox (邮箱), 也可以是一组 mailbox.

address         =   mailbox / group

mailbox = name-addr / addr-spec

name-addr = [display-name] angle-addr

angle-addr = [CFWS] "`<" addr-spec ">`" [CFWS] /
obs-angle-addr

group = display-name ":" [group-list] ";" [CFWS]

display-name = phrase

mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list

address-list = (address *("," address)) / obs-addr-list

group-list = mailbox-list / CFWS / obs-group-list

地址示例:

简单形式 (仅地址):
[email protected]

完整形式 (带显示名):
Alice Smith ``<[email protected]>``
"Joe Q. Public" ``<[email protected]>``

多个接收者:
To: [email protected], [email protected]

组地址:
To: Development Team: [email protected], [email protected];

3.4.1. Addr-Spec 规范

addr-spec 是一种特定的 Internet 标识符, 其中包含一个本地解释的字符串, 后跟 at-sign 字符 ("@", ASCII 值 64), 再后跟一个 Internet 域.

addr-spec       =   local-part "@" domain

local-part = dot-atom / quoted-string / obs-local-part

domain = dot-atom / domain-literal / obs-domain

domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]

dtext = %d33-90 / ; Printable US-ASCII
%d94-126 / ; characters not including
obs-dtext ; "[", "]", or "\"

地址示例:

标准格式:
[email protected]
[email protected]

带引用的 local part:
"joe smith"@example.com

Domain literal (IP 地址):
user@[192.0.2.1]

第 3 章摘要

关键语法元素

消息结构层次:

Message
├── Lexical Tokens
│ ├── atom, quoted-string
│ ├── word, phrase
│ └── comment, FWS
├── Date-Time
│ └── Day, DD Mon YYYY HH:MM:SS +ZZZZ
└── Address
├── mailbox: name ``<user@domain>``
└── group: name: addr1, addr2;

实现检查清单

  • 正确处理 folding white space (FWS, 折叠空白)
  • 支持注释 (嵌套圆括号)
  • 解析 quoted-string 和 quoted-pair
  • 验证 date-time 格式和有效性
  • 解析 mailbox 和 group 地址
  • 处理 local-part 和 domain
  • 支持过时语法 (仅解析, 不生成)

下一节: 4. 过时语法

上一节: 2. 消息的词法分析