跳到主要内容

9. 正式语法

RFC 3501 IMAPv4 March 2003

  1.  IMAP4rev1 连接示例

    以下是一个 IMAP4rev1 连接的交互记录. 为便于编辑阅读, 本示例中的长行被折行.

S: * OK IMAP4rev1 Service Ready C: a001 login mrc secret S: a001 OK LOGIN completed C: a002 select inbox S: * 18 EXISTS S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) S: * 2 RECENT S: * OK [UNSEEN 17] Message 17 is the first unseen message S: * OK [UIDVALIDITY 3857529045] UIDs valid S: a002 OK [READ-WRITE] SELECT completed C: a003 fetch 12 full S: * 12 FETCH (FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700" RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)" "IMAP4rev1 WG mtg summary and minutes" (("Terry Gray" NIL "gray" "cac.washington.edu")) (("Terry Gray" NIL "gray" "cac.washington.edu")) (("Terry Gray" NIL "gray" "cac.washington.edu")) ((NIL NIL "imap" "cac.washington.edu")) ((NIL NIL "minutes" "CNRI.Reston.VA.US") ("John Klensin" NIL "KLENSIN" "MIT.EDU")) NIL NIL "<[email protected]>") BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 3028 92)) S: a003 OK FETCH completed C: a004 fetch 12 body[header] S: * 12 FETCH (BODY[HEADER] \{342\} S: Date: Wed, 17 Jul 1996 02:23:25 -0700 (PDT) S: From: Terry Gray <[email protected]> S: Subject: IMAP4rev1 WG mtg summary and minutes S: To: [email protected] S: cc: [email protected], John Klensin <[email protected]> S: Message-Id: <[email protected]> S: MIME-Version: 1.0 S: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII S: S: ) S: a004 OK FETCH completed C: a005 store 12 +flags \deleted S: * 12 FETCH (FLAGS (\Seen \Deleted)) S: a005 OK +FLAGS completed C: a006 logout S: * BYE IMAP4rev1 server terminating connection S: a006 OK LOGOUT completed

RFC 3501 IMAPv4 March 2003

  1.  正式语法

    以下语法规范使用 [ABNF] 中规定的扩展巴科斯-瑙尔范式 (Augmented Backus-Naur Form, ABNF) 表示法.

    对于备选规则或可选规则, 如果后面的规则与前面的规则重叠, 则较早列出的规则 MUST 优先. 例如, "\Seen" 在作为 flag 解析时是 \Seen 标志名, 而不是 flag-extension, 即使 "\Seen" 也可以解析为 flag-extension. 下面标注了此规则的一些实例, 但并非全部实例.

     注意: [ABNF] 规则 MUST 被严格遵守; 特别是:

    (1) 除非另有说明, 所有字母字符均不区分大小写. 使用大写或小写字符定义 token 字符串仅为编辑清晰性. 实现 MUST 以不区分大小写的方式接受这些字符串.

    (2) 在所有情况下, SP 均指恰好一个空格. 不允许用 TAB 替代, 插入额外空格, 或以其他方式将 SP 视为等同于 LWSP.

    (3) ASCII NUL 字符 %x00 在任何时候都 MUST NOT 使用.

address = "(" addr-name SP addr-adl SP addr-mailbox SP addr-host ")"

addr-adl = nstring ; Holds route from [RFC-2822] route-addr if ; non-NIL

addr-host = nstring ; NIL indicates [RFC-2822] group syntax. ; Otherwise, holds [RFC-2822] domain name

addr-mailbox = nstring ; NIL indicates end of [RFC-2822] group; if ; non-NIL and addr-host is NIL, holds ; [RFC-2822] group name. ; Otherwise, holds [RFC-2822] local-part ; after removing [RFC-2822] quoting

RFC 3501 IMAPv4 March 2003

addr-name = nstring ; If non-NIL, holds phrase from [RFC-2822] ; mailbox after removing [RFC-2822] quoting

append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP literal

astring = 1*ASTRING-CHAR / string

ASTRING-CHAR = ATOM-CHAR / resp-specials

atom = 1*ATOM-CHAR

ATOM-CHAR = <any CHAR except atom-specials>

atom-specials = "(" / ")" / "\{" / SP / CTL / list-wildcards / quoted-specials / resp-specials

authenticate = "AUTHENTICATE" SP auth-type *(CRLF base64)

auth-type = atom ; Defined by [SASL]

base64 = *(4base64-char) [base64-terminal]

base64-char = ALPHA / DIGIT / "+" / "/" ; Case-sensitive

base64-terminal = (2base64-char "==") / (3base64-char "=")

body = "(" (body-type-1part / body-type-mpart) ")"

body-extension = nstring / number / "(" body-extension *(SP body-extension) ")" ; Future expansion. Client implementations ; MUST accept body-extension fields. Server ; implementations MUST NOT generate ; body-extension fields except as defined by ; future standard or standards-track ; revisions of this specification.

body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] ; MUST NOT be returned on non-extensible ; "BODY" fetch

RFC 3501 IMAPv4 March 2003

body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] ; MUST NOT be returned on non-extensible ; "BODY" fetch

body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP body-fld-enc SP body-fld-octets

body-fld-desc = nstring

body-fld-dsp = "(" string SP body-fld-param ")" / nil

body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ "QUOTED-PRINTABLE") DQUOTE) / string

body-fld-id = nstring

body-fld-lang = nstring / "(" string *(SP string) ")"

body-fld-loc = nstring

body-fld-lines = number

body-fld-md5 = nstring

body-fld-octets = number

body-fld-param = "(" string SP string *(SP string SP string) ")" / nil

body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part]

body-type-basic = media-basic SP body-fields ; MESSAGE subtype MUST NOT be "RFC822"

body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart]

body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines

body-type-text = media-text SP body-fields SP body-fld-lines

capability = ("AUTH=" auth-type) / atom ; New capabilities MUST begin with "X" or be ; registered with IANA as standard or ; standards-track

RFC 3501 IMAPv4 March 2003

capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1" *(SP capability) ; Servers MUST implement the STARTTLS, AUTH=PLAIN, ; and LOGINDISABLED capabilities ; Servers which offer RFC 1730 compatibility MUST ; list "IMAP4" as the first capability.

CHAR8 = %x01-ff ; any OCTET except NUL, %x00

command = tag SP (command-any / command-auth / command-nonauth / command-select) CRLF ; Modal based on state

command-any = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command ; Valid in all states

command-auth = append / create / delete / examine / list / lsub / rename / select / status / subscribe / unsubscribe ; Valid only in Authenticated or Selected state

command-nonauth = login / authenticate / "STARTTLS" ; Valid only when in Not Authenticated state

command-select = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store / uid / search ; Valid only when in Selected state

continue-req = "+" SP (resp-text / base64) CRLF

copy = "COPY" SP sequence-set SP mailbox

create = "CREATE" SP mailbox ; Use of INBOX gives a NO error

date = date-text / DQUOTE date-text DQUOTE

date-day = 1*2DIGIT ; Day of month

date-day-fixed = (SP DIGIT) / 2DIGIT ; Fixed-format version of date-day

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

date-text = date-day "-" date-month "-" date-year

RFC 3501 IMAPv4 March 2003

date-year = 4DIGIT

date-time = DQUOTE date-day-fixed "-" date-month "-" date-year SP time SP zone DQUOTE

delete = "DELETE" SP mailbox ; Use of INBOX gives a NO error

digit-nz = %x31-39 ; 1-9

envelope = "(" env-date SP env-subject SP env-from SP env-sender SP env-reply-to SP env-to SP env-cc SP env-bcc SP env-in-reply-to SP env-message-id ")"

env-bcc = "(" 1*address ")" / nil

env-cc = "(" 1*address ")" / nil

env-date = nstring

env-from = "(" 1*address ")" / nil

env-in-reply-to = nstring

env-message-id = nstring

env-reply-to = "(" 1*address ")" / nil

env-sender = "(" 1*address ")" / nil

env-subject = nstring

env-to = "(" 1*address ")" / nil

examine = "EXAMINE" SP mailbox

fetch = "FETCH" SP sequence-set SP ("ALL" / "FULL" / "FAST" / fetch-att / "(" fetch-att *(SP fetch-att) ")")

fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" / "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] / "BODY" ["STRUCTURE"] / "UID" / "BODY" section ["<" number "." nz-number ">"] / "BODY.PEEK" section ["<" number "." nz-number ">"]

RFC 3501 IMAPv4 March 2003

flag = "\Answered" / "\Flagged" / "\Deleted" / "\Seen" / "\Draft" / flag-keyword / flag-extension ; Does not include "\Recent"

flag-extension = "" atom ; Future expansion. Client implementations ; MUST accept flag-extension flags. Server ; implementations MUST NOT generate ; flag-extension flags except as defined by ; future standard or standards-track ; revisions of this specification.

flag-fetch = flag / "\Recent"

flag-keyword = atom

flag-list = "(" [flag *(SP flag)] ")"

flag-perm = flag / "*"

greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF

header-fld-name = astring

header-list = "(" header-fld-name *(SP header-fld-name) ")"

list = "LIST" SP mailbox SP list-mailbox

list-mailbox = 1*list-char / string

list-char = ATOM-CHAR / list-wildcards / resp-specials

list-wildcards = "%" / "*"

literal = "\{" number "\}" CRLF *CHAR8 ; Number represents the number of CHAR8s

login = "LOGIN" SP userid SP password

lsub = "LSUB" SP mailbox SP list-mailbox

RFC 3501 IMAPv4 March 2003

mailbox = "INBOX" / astring ; INBOX is case-insensitive. All case variants of ; INBOX (e.g., "iNbOx") MUST be interpreted as INBOX ; not as an astring. An astring which consists of ; the case-insensitive sequence "I" "N" "B" "O" "X" ; is considered to be INBOX and not an astring. ; Refer to section 5.1 for further ; semantic details of mailbox names.

mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list / "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) / "STATUS" SP mailbox SP "(" [status-att-list] ")" / number SP "EXISTS" / number SP "RECENT"

mailbox-list = "(" [mbx-list-flags] ")" SP (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox

mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag *(SP mbx-list-oflag) / mbx-list-oflag *(SP mbx-list-oflag)

mbx-list-oflag = "\Noinferiors" / flag-extension ; Other flags; multiple possible per LIST response

mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked" ; Selectability flags; only one per LIST response

media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" / "VIDEO") DQUOTE) / string) SP media-subtype ; Defined in [MIME-IMT]

media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE ; Defined in [MIME-IMT]

media-subtype = string ; Defined in [MIME-IMT]

media-text = DQUOTE "TEXT" DQUOTE SP media-subtype ; Defined in [MIME-IMT]

message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))

msg-att = "(" (msg-att-dynamic / msg-att-static) *(SP (msg-att-dynamic / msg-att-static)) ")"

msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")" ; MAY change for a message

RFC 3501 IMAPv4 March 2003

msg-att-static = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time / "RFC822" [".HEADER" / ".TEXT"] SP nstring / "RFC822.SIZE" SP number / "BODY" ["STRUCTURE"] SP body / "BODY" section ["<" number ">"] SP nstring / "UID" SP uniqueid ; MUST NOT change for a message

nil = "NIL"

nstring = string / nil

number = 1*DIGIT ; Unsigned 32-bit integer ; (0 <= n < 4,294,967,296)

nz-number = digit-nz *DIGIT ; Non-zero unsigned 32-bit integer ; (0 < n < 4,294,967,296)

password = astring

quoted = DQUOTE *QUOTED-CHAR DQUOTE

QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "" quoted-specials

quoted-specials = DQUOTE / ""

rename = "RENAME" SP mailbox SP mailbox ; Use of INBOX as a destination gives a NO error

response = *(continue-req / response-data) response-done

response-data = "*" SP (resp-cond-state / resp-cond-bye / mailbox-data / message-data / capability-data) CRLF

response-done = response-tagged / response-fatal

response-fatal = "*" SP resp-cond-bye CRLF ; Server closes connection immediately

response-tagged = tag SP resp-cond-state CRLF

resp-cond-auth = ("OK" / "PREAUTH") SP resp-text ; Authentication condition

RFC 3501 IMAPv4 March 2003

resp-cond-bye = "BYE" SP resp-text

resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text ; Status condition

resp-specials = "]"

resp-text = ["[" resp-text-code "]" SP] text

resp-text-code = "ALERT" / "BADCHARSET" [SP "(" astring *(SP astring) ")" ] / capability-data / "PARSE" / "PERMANENTFLAGS" SP "(" [flag-perm (SP flag-perm)] ")" / "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number / "UNSEEN" SP nz-number / atom [SP 1<any TEXT-CHAR except "]">]

search = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key) ; CHARSET argument to MUST be registered with IANA

search-key = "ALL" / "ANSWERED" / "BCC" SP astring / "BEFORE" SP date / "BODY" SP astring / "CC" SP astring / "DELETED" / "FLAGGED" / "FROM" SP astring / "KEYWORD" SP flag-keyword / "NEW" / "OLD" / "ON" SP date / "RECENT" / "SEEN" / "SINCE" SP date / "SUBJECT" SP astring / "TEXT" SP astring / "TO" SP astring / "UNANSWERED" / "UNDELETED" / "UNFLAGGED" / "UNKEYWORD" SP flag-keyword / "UNSEEN" / ; Above this line were in [IMAP2] "DRAFT" / "HEADER" SP header-fld-name SP astring / "LARGER" SP number / "NOT" SP search-key / "OR" SP search-key SP search-key / "SENTBEFORE" SP date / "SENTON" SP date / "SENTSINCE" SP date / "SMALLER" SP number / "UID" SP sequence-set / "UNDRAFT" / sequence-set / "(" search-key *(SP search-key) ")"

section = "[" [section-spec] "]"

section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list / "TEXT" ; top-level or MESSAGE/RFC822 part

section-part = nz-number *("." nz-number) ; body part nesting

RFC 3501 IMAPv4 March 2003

section-spec = section-msgtext / (section-part ["." section-text])

section-text = section-msgtext / "MIME" ; text other than actual body part (headers, etc.)

select = "SELECT" SP mailbox

seq-number = nz-number / "" ; message sequence number (COPY, FETCH, STORE ; commands) or unique identifier (UID COPY, ; UID FETCH, UID STORE commands). ; * represents the largest number in use. In ; the case of message sequence numbers, it is ; the number of messages in a non-empty mailbox. ; In the case of unique identifiers, it is the ; unique identifier of the last message in the ; mailbox or, if the mailbox is empty, the ; mailbox's current UIDNEXT value. ; The server should respond with a tagged BAD ; response to a command that uses a message ; sequence number greater than the number of ; messages in the selected mailbox. This ; includes "" if the selected mailbox is empty.

seq-range = seq-number ":" seq-number ; two seq-number values and all values between ; these two regardless of order. ; Example: 2:4 and 4:2 are equivalent and indicate ; values 2, 3, and 4. ; Example: a unique identifier sequence range of ; 3291:* includes the UID of the last message in ; the mailbox, even if that value is less than 3291.

sequence-set = (seq-number / seq-range) ("," sequence-set) ; set of seq-number values, regardless of order. ; Servers MAY coalesce overlaps and/or execute the ; sequence in any order. ; Example: a message sequence number set of ; 2,4:7,9,12: for a mailbox with 15 messages is ; equivalent to 2,4,5,6,7,9,12,13,14,15 ; Example: a message sequence number set of *:4,5:7 ; for a mailbox with 10 messages is equivalent to ; 10,9,8,7,6,5,4,5,6,7 and MAY be reordered and ; overlap coalesced to be 4,5,6,7,8,9,10.

status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")"

RFC 3501 IMAPv4 March 2003

status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" / "UNSEEN"

status-att-list = status-att SP number *(SP status-att SP number)

store = "STORE" SP sequence-set SP store-att-flags

store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP (flag-list / (flag *(SP flag)))

string = quoted / literal

subscribe = "SUBSCRIBE" SP mailbox

tag = 1*<any ASTRING-CHAR except "+">

text = 1*TEXT-CHAR

TEXT-CHAR = <any CHAR except CR and LF>

time = 2DIGIT ":" 2DIGIT ":" 2DIGIT ; Hours minutes seconds

uid = "UID" SP (copy / fetch / search / store) ; Unique identifiers used instead of message ; sequence numbers

uniqueid = nz-number ; Strictly ascending

unsubscribe = "UNSUBSCRIBE" SP mailbox

userid = astring

x-command = "X" atom <experimental command arguments>

zone = ("+" / "-") 4DIGIT ; Signed four-digit value of hhmm representing ; hours and minutes east of Greenwich (that is, ; the amount that the given time differs from ; Universal Time). Subtracting the timezone ; from the given time will give the UT form. ; The Universal Time zone is "+0000".

RFC 3501 IMAPv4 March 2003

  1. 作者说明

本文档是对早期文档的修订或重写, 并取代这些文档中的协议规范: RFC 2060, RFC 1730, 未发布的 IMAP2bis.TXT 文档, RFC 1176, RFC 1064.

  1. 安全考虑事项

除非协商了防窥探保护, 否则 IMAP4rev1 协议事务 (包括电子邮件数据) 会以明文在网络上传输. 这可以通过使用 STARTTLS, 在 AUTHENTICATE 命令中协商隐私保护, 或使用其他保护机制来实现.

11.1. STARTTLS 安全考虑事项

本文档中 STARTTLS 命令和 LOGINDISABLED 能力的规范取代 [IMAP-TLS] 中的对应内容. [IMAP-TLS] 对 PLAIN [SASL] 认证器仍具有规范性.

IMAP 客户端和服务器实现 MUST 实现 TLS_RSA_WITH_RC4_128_MD5 [TLS] 密码套件, 并 SHOULD 实现 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [TLS] 密码套件. 这一点很重要, 因为它确保任意两个符合规范的实现都可以配置为互操作. 所有其他密码套件都是 OPTIONAL. 注意, 这是相对于 [IMAP-TLS] 第 2.1 节的变更.

在 [TLS] 协商期间, 客户端 MUST 将其理解的服务器主机名与服务器在 Certificate 消息中呈现的身份进行检查, 以防止中间人攻击. 如果匹配失败, 客户端 SHOULD 请求用户明确确认, 或终止连接并指示服务器身份可疑. 匹配按以下规则执行:

    客户端 MUST 使用其用于打开连接的服务器主机名, 作为与服务器证书中表示的服务器名称进行比较的值. 客户端 MUST NOT 使用从不安全远程来源 (例如不安全的 DNS 查询) 派生的任何形式的服务器主机名. 不执行 CNAME 规范化.

如果证书中存在 dNSName 类型的 subjectAltName 扩展, 则 SHOULD 使用它作为服务器身份的来源.

匹配不区分大小写.

RFC 3501 IMAPv4 March 2003

    "*" 通配符字符 MAY 用作证书中最左侧的名称组件. 例如, *.example.com 会匹配 a.example.com, foo.example.com 等, 但不会匹配 example.com.

如果证书包含多个名称 (例如多个 dNSName 字段), 则与其中任一字段匹配即视为可接受.

客户端和服务器都 MUST 检查 STARTTLS 命令以及后续 [TLS] 协商的结果, 以确定是否达到了可接受的认证或隐私保护.

11.2. 其他安全考虑事项

对于因凭据无效而失败的 AUTHENTICATE 命令, 服务器错误消息 SHOULD NOT 详细说明凭据无效的原因.

使用 LOGIN 命令会以明文发送密码. 可以通过以下方式避免这一点: 使用带有不使用明文密码的 [SASL] 机制的 AUTHENTICATE 命令, 或先通过 STARTTLS 或其他保护机制协商加密.

服务器实现 MUST 实现一种配置, 要求在认证时满足以下条件: (1) STARTTLS 命令已经协商. OR (2) 已提供某种其他机制, 用于保护会话免受密码窥探. OR (3) 以下措施已经到位: (a) 通告 LOGINDISABLED 能力, 并且 CAPABILITY 列表中 NOT 通告使用明文密码的 [SASL] 机制 (如 PLAIN). AND (b) 即使密码正确, LOGIN 命令也返回错误. AND (c) 对所有使用明文密码的 [SASL] 机制, 即使密码正确, AUTHENTICATE 命令也返回错误.

对于失败的 LOGIN 命令, 服务器错误消息 SHOULD NOT 指明无效的是用户名而不是密码.