class Net::IMAP
Net::IMAP
实现了 Internet 消息访问协议 (IMAP) 客户端功能。该协议在 IMAP4rev1 [RFC3501] 和 IMAP4rev2 [RFC9051] 中进行了描述。
IMAP 概述¶ ↑
IMAP 客户端连接到服务器,然后使用 authenticate
或 login
进行身份验证。完成身份验证后,可以使用一系列命令。大多数命令处理邮箱,邮箱可以排列在分层命名空间中,每个邮箱包含零个或多个消息。这在服务器上的实现方式取决于实现;在 UNIX 服务器上,通常会将其实现为目录层次结构中的邮箱格式的文件。
要处理邮箱中的消息,客户端必须先使用 select
或 examine
(用于只读访问)选择该邮箱。客户端成功选择邮箱后,将进入“selected”状态,并且该邮箱将成为当前邮箱,与邮件项相关的命令会隐式地在该邮箱上操作。
序列号和 UID¶ ↑
消息有两种类型的标识符:消息序列号和 UID。
消息序列号从 1 开始对邮箱内的消息进行编号,直到邮箱中的项目数。如果会话期间收到新消息,则该消息的序列号等于邮箱的新大小。如果从邮箱中删除消息,则剩余消息的序列号将“向下洗牌”以填补空白。
为避免序列号竞争条件,服务器在没有命令正在进行时,或者在响应 fetch
、store
或 search
时,不得删除消息。删除可能在任何其他命令期间发送,包括 uid_fetch
、uid_store
和 uid_search
。noop
和 idle
命令都对此副作用很有用:它们允许服务器发送所有邮箱更新,包括删除。
另一方面,UID 永久保证不会识别同一邮箱内的另一条消息,即使现有消息被删除也是如此。UID 必须在邮箱内按升序(但不一定是连续)顺序分配;这意味着如果非 IMAP 客户端重新排列邮箱内邮件项的顺序,则必须重新分配 UID。因此,IMAP 客户端无法重新排列消息顺序。
使用示例¶ ↑
列出默认邮箱中所有最近邮件的发送者和主题¶ ↑
imap = Net::IMAP.new('mail.example.com') imap.authenticate('PLAIN', 'joe_user', 'joes_password') imap.examine('INBOX') imap.search(["RECENT"]).each do |message_id| envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"] puts "#{envelope.from[0].name}: \t#{envelope.subject}" end
将 2003 年 4 月的所有邮件从“Mail/sent-mail”移动到“Mail/sent-apr03”¶ ↑
imap = Net::IMAP.new('mail.example.com') imap.authenticate('PLAIN', 'joe_user', 'joes_password') imap.select('Mail/sent-mail') if not imap.list('Mail/', 'sent-apr03') imap.create('Mail/sent-apr03') end imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id| imap.copy(message_id, "Mail/sent-apr03") imap.store(message_id, "+FLAGS", [:Deleted]) end imap.expunge
功能¶ ↑
大多数 Net::IMAP
方法目前不会根据服务器通告的 capabilities
修改其行为。此类用户必须在发送扩展命令或命令参数之前检查服务器是否能够支持它们。应特别注意遵循 capabilities
对 starttls
、login
和 authenticate
的要求。
请参阅 capable?
、auth_capable?
、capabilities
、auth_mechanisms
以发现服务器功能。有关相关功能要求,请参阅每个 IMAP 命令的文档。
imap = Net::IMAP.new("mail.example.com") imap.capable?(:IMAP4rev1) or raise "Not an IMAP4rev1 server" imap.capable?(:starttls) or raise "Cannot start TLS" imap.starttls if imap.auth_capable?("PLAIN") imap.authenticate "PLAIN", username, password elsif !imap.capability?("LOGINDISABLED") imap.login username, password else raise "No acceptable authentication mechanisms" end # Support for "UTF8=ACCEPT" implies support for "ENABLE" imap.enable :utf8 if imap.capable?("UTF8=ACCEPT") namespaces = imap.namespace if imap.capable?(:namespace) mbox_prefix = namespaces&.personal&.first&.prefix || "" mbox_delim = namespaces&.personal&.first&.delim || "/" mbox_path = prefix + %w[path to my mailbox].join(delim) imap.create mbox_path
基本的 IMAP4rev1 功能¶ ↑
IMAP4rev1 服务器必须在其功能列表中通告 IMAP4rev1
。IMAP4rev1 服务器必须实现 STARTTLS
、AUTH=PLAIN
和 LOGINDISABLED
功能。有关这些功能的含义,请参阅 starttls
、login
和 authenticate
。
缓存 CAPABILITY
响应¶ ↑
Net::IMAP
会根据 IMAP4rev2 §6.1.1、§6.2 和 §7.1 中的要求和建议,自动存储和丢弃功能数据。请使用 capable?
、auth_capable?
或 capabilities
来使用此缓存并避免不必要地发送 capability
命令。
服务器可以使用 PREAUTH
或 OK
greeting
中的 CAPABILITY
ResponseCode
通告其初始功能。当 TLS 启动 (starttls
) 且完成身份验证 (login
或 authenticate
) 后,服务器的功能可能会更改,并且缓存的功能将被丢弃。服务器可以使用 login
或 authenticate
的 OK
TaggedResponse
发送更新的功能,这些功能将由 Net::IMAP
缓存。但是,必须忽略 starttls
的 TaggedResponse
,它在 TLS 启动之前发送并且不受保护。
将功能值存储到变量时,请注意它们是否已正确丢弃或重置,尤其是在 starttls
之后。
使用 IMAP4rev1 扩展¶ ↑
有关所有标准功能及其参考 RFC 的列表,请参阅 IANA IMAP4 功能注册表。
IMAP4rev1 服务器在客户端显式调用某个功能(例如,发送特定于该功能的命令或命令参数)之前,不得激活与基本规范不兼容的行为。服务器可以在任何时候发送具有向后兼容行为的数据,例如响应代码或邮箱属性,而无需客户端操作。
调用 Net::IMAP
未知的功能可能会导致意外的行为和错误。例如,当收到未知的响应语法时,会引发 ResponseParseError
。调用服务器不支持的命令或命令参数可能会引发 NoResponseError
、BadResponseError
或导致其他意外行为。
某些功能必须使用 enable
命令显式激活。有关详细信息,请参见 enable
。
线程安全¶ ↑
Net::IMAP
支持并发线程。例如:
imap = Net::IMAP.new("imap.foo.net", "imap2") imap.authenticate("scram-md5", "bar", "password") imap.select("inbox") fetch_thread = Thread.start { imap.fetch(1..-1, "UID") } search_result = imap.search(["BODY", "hello"]) fetch_result = fetch_thread.value imap.disconnect
此脚本并发调用 FETCH 命令和 SEARCH 命令。
错误¶ ↑
IMAP 服务器可以发送三种不同类型的响应来指示失败:
- NO
-
尝试的命令无法成功完成。例如,用于登录的用户名/密码不正确;所选的邮箱不存在;等等。
- BAD
-
客户端的请求不符合服务器对 IMAP 协议的理解。这包括在错误的客户端状态下尝试命令;例如,在没有 SELECT 当前邮箱的情况下尝试执行 SEARCH 命令。它还可以表示发生了内部服务器故障(例如磁盘崩溃)。
- BYE
-
服务器正在说再见。这可能是正常注销序列的一部分,也可以作为登录序列的一部分,表示服务器(由于某种原因)不愿意接受您的连接。作为对任何其他命令的响应,它表示服务器正在关闭,或者服务器由于不活动而使客户端连接超时。
这三种错误响应分别由错误 Net::IMAP::NoResponseError
、Net::IMAP::BadResponseError
和 Net::IMAP::ByeResponseError
表示,它们都是 Net::IMAP::ResponseError
的子类。本质上,所有涉及向服务器发送请求的方法都可能产生这些错误之一。下面只记录了最相关的实例。
由于 IMAP
类使用套接字进行通信,因此其方法也容易受到在使用套接字时可能发生的各种错误的影响。这些错误通常表示为 Errno 错误。例如,任何涉及向服务器发送请求和/或接收服务器响应的方法,如果网络连接意外中断,都可能引发 Errno::EPIPE 错误。请参见 socket(7)、ip(7)、tcp(7)、socket(2)、connect(2) 和相关的 man 页面。
最后,如果发现底层数据格式不正确(例如,在 UTF-8 和 UTF-16 之间转换时),则会抛出 Net::IMAP::DataFormatError
;如果服务器响应不可解析,则会抛出 Net::IMAP::ResponseParseError
。
这里有什么?¶ ↑
连接控制方法¶ ↑
-
Net::IMAP.new
:创建一个新的 IMAP 客户端,该客户端会立即连接并等待服务器成功问候,然后该方法返回。 -
starttls
:要求服务器将明文连接升级为使用 TLS。 -
logout
:告诉服务器结束会话。进入“注销”状态。 -
disconnect
:断开连接(不首先发送logout
)。 -
disconnected?
:如果连接已关闭,则为 True。
服务器功能¶ ↑
-
capable?
:返回服务器是否支持给定的功能。 -
capabilities
:以字符串数组的形式返回服务器的功能。 -
auth_capable?
:返回服务器是否声明支持给定的SASL
机制,用于authenticate
。 -
auth_mechanisms
:以字符串数组的形式返回服务器声明支持的authenticate
SASL
机制。 -
clear_cached_capabilities
:清除缓存的功能。在完成 #starttls、#login 或 #authenticate 后,功能缓存会自动清除。
-
capability
:发送CAPABILITY
命令并返回capabilities
。通常,应使用 #capable? 而不是显式向服务器发送
CAPABILITY
命令。
处理服务器响应¶ ↑
-
greeting
:服务器的初始未标记响应,可以指示预认证的连接。 -
responses
:产生未处理的UntaggedResponse#data
和 非nil
的ResponseCode#data
。 -
extract_responses
:删除并返回块返回 true 值的响应。 -
clear_responses
:从responses
中删除未处理的数据并返回。 -
add_response_handler
:添加一个块,以便在接收器线程中使用每个服务器响应调用。 -
response_handlers
:返回响应处理程序的列表。 -
remove_response_handler
:删除先前添加的响应处理程序。
核心 IMAP 命令¶ ↑
以下命令由 [IMAP4rev1] 基本规范或以下扩展之一定义:[IDLE]、[NAMESPACE]、[UNSELECT]、[ENABLE]、[MOVE]。这些扩展被现代 IMAP4rev1 服务器广泛支持,并且都已集成到 [IMAP4rev2] 中。注意: Net::IMAP 尚未支持 IMAP4rev2。
任何状态¶ ↑
-
capability
:以字符串数组的形式返回服务器的功能。通常,应使用 #capable? 而不是显式向服务器发送
CAPABILITY
命令。 -
logout
:告诉服务器结束会话。进入“注销”状态。
未认证状态¶ ↑
除了任何状态的命令之外,以下命令在“未认证”状态下有效:
-
starttls
:将明文连接升级为使用 TLS。需要
STARTTLS
功能。 -
authenticate
:使用给定的 SASL 机制 和凭据向服务器标识客户端。进入“已认证”状态。服务器应列出受支持机制的
"AUTH=#{mechanism}"
功能。 -
login
:使用纯文本密码向服务器标识客户端。通常首选使用authenticate
。进入“已认证”状态。不得列出
LOGINDISABLED
功能。
已认证状态¶ ↑
除了任何状态的命令之外,以下命令在“已认证”状态下有效:
-
enable
:启用向后不兼容的服务器扩展。需要ENABLE
或IMAP4rev2
功能。 -
select
:打开邮箱并进入“已选择”状态。 -
examine
:以只读方式打开邮箱,并进入“已选择”状态。 -
create
:创建一个新的邮箱。 -
delete
:永久删除一个邮箱。 -
rename
:更改邮箱的名称。 -
subscribe
:将邮箱添加到“已订阅”集合中。 -
unsubscribe
:从“已订阅”集合中删除邮箱。 -
list
:返回与给定模式匹配的邮箱的名称和属性。 -
namespace
:返回邮箱命名空间,带有路径前缀和分隔符。需要NAMESPACE
或IMAP4rev2
功能。 -
status
:返回邮箱信息,例如消息计数、未读消息计数、UIDVALIDITY
和UIDNEXT
。 -
append
:将消息附加到邮箱的末尾。 -
idle
:允许服务器向客户端发送更新,而无需客户端使用noop
进行轮询。需要IDLE
或IMAP4rev2
功能。 -
已过时
lsub
:已由LIST-EXTENDED
替换,并从IMAP4rev2
中删除。 列出“已订阅”集合中的邮箱。注意: Net::IMAP 尚未实现
LIST-EXTENDED
。
已选择状态¶ ↑
除了任何状态的命令和“已认证”命令之外,以下命令在“已选择”状态下有效:
-
close
:关闭邮箱并返回“已认证”状态,删除已删除的消息,除非邮箱以只读方式打开。 -
unselect
:关闭邮箱并返回“已认证”状态,而不删除任何消息。需要UNSELECT
或IMAP4rev2
功能。 -
expunge
:永久删除设置了 Deleted 标志的消息。 -
uid_expunge
:限制删除操作仅删除指定的 UID。需要UIDPLUS
或IMAP4rev2
功能。 -
search
、uid_search
:返回与给定搜索条件匹配的消息的序列号或 UID。 -
move
、uid_move
:将指定的消息移动到指定目标邮箱的末尾,并从当前邮箱中删除它们。需要MOVE
或IMAP4rev2
功能。
注销状态¶ ↑
在“注销”状态下,任何 IMAP 命令均无效。如果套接字仍然打开,Net::IMAP
将在收到服务器确认后关闭它。已启动并正在等待响应的 IMAP 命令,以及注销后调用的任何命令都会引发异常。
IMAP 扩展支持¶ ↑
RFC9051: IMAP4rev2
¶ ↑
尽管 IMAP4rev2 尚未完全支持,但 Net::IMAP
支持已纳入其中的几个扩展:ENABLE
、IDLE
、MOVE
、NAMESPACE
、SASL-IR
、UIDPLUS
、UNSELECT
、STATUS=SIZE
以及 BINARY
的提取端。这些扩展的命令与上面的 核心 IMAP 命令一起列出。
以下扩展已纳入
IMAP4rev2
,但目前Net::IMAP
不支持或不完全支持:RFC4466 扩展、SEARCHRES
、LIST-EXTENDED
、LIST-STATUS
、LITERAL-
和SPECIAL-USE
。
RFC2087: QUOTA
¶ ↑
-
getquota
:返回配额根的资源使用情况和限制 -
getquotaroot
:返回邮箱的配额根列表,以及它们的资源使用情况和限制。 -
setquota
:设置给定配额根的资源限制。
RFC2177: IDLE
¶ ↑
已纳入 IMAP4rev2,并且也包含在上面的 核心 IMAP 命令中。
RFC2342: NAMESPACE
¶ ↑
已纳入 IMAP4rev2,并且也包含在上面的 核心 IMAP 命令中。
-
namespace
:返回带有路径前缀和分隔符的邮箱命名空间。
RFC2971: ID
¶ ↑
-
id
:交换客户端和服务器的实现信息。
RFC3516: BINARY
¶ ↑
BINARY
的提取端已纳入 IMAP4rev2。
-
使用
BINARY
、BINARY.PEEK
和BINARY.SIZE
项更新fetch
和uid_fetch
。请参阅FetchData#binary
和FetchData#binary_size
。
注意:
append
命令的二进制扩展目前不受支持。
RFC3691: UNSELECT
¶ ↑
已纳入 IMAP4rev2,并且也包含在上面的 核心 IMAP 命令中。
-
unselect
:关闭邮箱并返回到“已验证”状态,而不清除任何邮件。
RFC4314: ACL
¶ ↑
注意: 目前不支持
DELETEACL
、LISTRIGHTS
和MYRIGHTS
。
RFC4315: UIDPLUS
¶ ↑
已纳入 IMAP4rev2,并且也包含在上面的 核心 IMAP 命令中。
-
uid_expunge
:限制expunge
仅删除指定的 UID。 -
使用
UIDNOTSTICKY
ResponseCode
更新select
,examine
-
使用
APPENDUID
ResponseCode
更新append
-
使用
COPYUID
ResponseCode
更新copy
,move
RFC4731: ESEARCH
¶ ↑
已纳入 IMAP4rev2。
-
使用
return
选项和ESearchResult
更新search
,uid_search
。
RFC4959: SASL-IR
¶ ↑
已纳入 IMAP4rev2。
-
使用发送初始响应的选项更新
authenticate
。
RFC5161: ENABLE
¶ ↑
已纳入 IMAP4rev2,并且也包含在上面的 核心 IMAP 命令中。
-
enable
:启用向后不兼容的服务器扩展。
RFC5256: SORT
¶ ↑
-
sort
,uid_sort
:search
或uid_search
的替代版本,它会按指定的键对结果进行排序。
RFC5256: THREAD
¶ ↑
-
thread
,uid_thread
:search
或uid_search
的替代版本,它会根据选择的算法将结果排列成有序的组或线程。
X-GM-EXT-1
¶ ↑
X-GM-EXT-1
是一个非标准的 Gmail 扩展。请参阅 Google 的文档。
-
使用对
X-GM-MSGID
(唯一消息 ID)、X-GM-THRID
(线程 ID)和X-GM-LABELS
(Gmail 标签)的支持更新fetch
和uid_fetch
。 -
使用
X-GM-RAW
搜索属性更新search
。
注意: OBJECTID
扩展应该替换 X-GM-MSGID
和 X-GM-THRID
,但 Gmail 不支持它(截至 2023-11-10)。
RFC6851: MOVE
¶ ↑
已纳入 IMAP4rev2,并且也包含在上面的 核心 IMAP 命令中。
RFC6855: UTF8=ACCEPT
, UTF8=ONLY
¶ ↑
-
有关支持 UTF-8 字符串编码的信息,请参阅
enable
。
RFC7162: CONDSTORE
¶ ↑
-
使用
CONDSTORE
参数更新enable
。通过使用以下列出的任何扩展的命令参数,也会启用CONDSTORE
。 -
使用
HIGHESTMODSEQ
状态属性更新status
。 -
使用
condstore
修饰符更新select
和examine
,并将HIGHESTMODSEQ
或NOMODSEQ
ResponseCode
添加到响应中。 -
使用
MODSEQ
搜索条件更新search
、uid_search
、sort
和uid_sort
,并将SearchResult#modseq
添加到搜索响应中。 -
使用
MODSEQ
搜索条件更新thread
和uid_thread
(但线程响应未更改)。 -
使用
changedsince
修饰符和MODSEQ
FetchData
属性更新fetch
和uid_fetch
。 -
使用
unchangedsince
修饰符更新store
和uid_store
,并将MODIFIED
ResponseCode
添加到标记的响应中。
RFC8438: STATUS=SIZE
¶ ↑
-
使用
SIZE
状态属性更新status
。
RFC8474: OBJECTID
¶ ↑
-
将
MAILBOXID
ResponseCode
添加到create
标记的响应中。 -
将
MAILBOXID
ResponseCode
添加到select
和examine
未标记的响应中。 -
使用
EMAILID
和THREADID
项更新fetch
和uid_fetch
。请参阅FetchData#emailid
和FetchData#emailid
。 -
使用对
MAILBOXID
状态属性的支持更新status
。
RFC9394: PARTIAL
¶ ↑
-
使用
PARTIAL
返回选项更新search
,uid_search
,它会添加ESearchResult#partial
返回数据。 -
使用
partial
修饰符更新uid_fetch
。
参考资料¶ ↑
- [IMAP4rev1]
-
Crispin, M., “INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1”, RFC 3501, DOI 10.17487/RFC3501, 2003 年 3 月, <www.rfc-editor.org/info/rfc3501>.
- [IMAP-ABNF-EXT]
-
Melnikov, A. 和 C. Daboo, “Collected Extensions to IMAP4 ABNF”, RFC 4466, DOI 10.17487/RFC4466, 2006 年 4 月, <www.rfc-editor.org/info/rfc4466>.
注意:Net::IMAP 尚无法解析整个 RFC4466 语法。
- [IMAP4rev2]
-
Melnikov, A., Ed. 和 B. Leiba, Ed., “Internet Message Access Protocol (IMAP) - Version 4rev2”, RFC 9051, DOI 10.17487/RFC9051, 2021 年 8 月, <www.rfc-editor.org/info/rfc9051>.
注意:Net::IMAP 尚未完全兼容 IMAP4rev2。
- [IMAP-IMPLEMENTATION]
-
Leiba, B., “IMAP4 Implementation Recommendations”, RFC 2683, DOI 10.17487/RFC2683, 1999 年 9 月, <www.rfc-editor.org/info/rfc2683>.
- [IMAP-MULTIACCESS]
-
Gahrns, M., “IMAP4 Multi-Accessed Mailbox Practice”, RFC 2180, DOI 10.17487/RFC2180, 1997 年 7 月, <www.rfc-editor.org/info/rfc2180>.
- [UTF7]
-
Goldsmith, D. 和 M. Davis, “UTF-7 A Mail-Safe Transformation Format of Unicode”, RFC 2152, DOI 10.17487/RFC2152, 1997 年 5 月, <www.rfc-editor.org/info/rfc2152>.
消息信封和正文结构¶ ↑
- [RFC5322]
-
Resnick, P., Ed., “Internet Message Format”, RFC 5322, DOI 10.17487/RFC5322, 2008 年 10 月, <www.rfc-editor.org/info/rfc5322>.
- [CHARSET]
-
Freed, N. 和 J. Postel,“IANA 字符集注册程序”,BCP 19,RFC 2978,DOI 10.17487/RFC2978,2000 年 10 月,<www.rfc-editor.org/info/rfc2978>。
- [DISPOSITION]
-
Troost, R.,Dorner, S. 和 K. Moore, Ed.,“在 Internet 消息中传递表示信息:Content-Disposition 头部字段”,RFC 2183,DOI 10.17487/RFC2183,1997 年 8 月,<www.rfc-editor.org/info/rfc2183>。
- [MIME-IMB]
-
Freed, N. 和 N. Borenstein,“多用途 Internet 邮件扩展 (MIME) 第一部分:Internet 消息主体的格式”,RFC 2045,DOI 10.17487/RFC2045,1996 年 11 月,<www.rfc-editor.org/info/rfc2045>。
- [MIME-IMT]
-
Freed, N. 和 N. Borenstein,“多用途 Internet 邮件扩展 (MIME) 第二部分:媒体类型”,RFC 2046,DOI 10.17487/RFC2046,1996 年 11 月,<www.rfc-editor.org/info/rfc2046>。
- [MIME-HDRS]
-
Moore, K.,“MIME(多用途 Internet 邮件扩展)第三部分:非 ASCII 文本的消息头扩展”,RFC 2047,DOI 10.17487/RFC2047,1996 年 11 月,<www.rfc-editor.org/info/rfc2047>。
- [RFC2231]
-
Freed, N. 和 K. Moore,“MIME 参数值和编码词扩展:字符集、语言和延续”,RFC 2231,DOI 10.17487/RFC2231,1997 年 11 月,<www.rfc-editor.org/info/rfc2231>。
- [I18n-HDRS]
-
Yang, A., Steele, S. 和 N. Freed,“国际化电子邮件头”,RFC 6532,DOI 10.17487/RFC6532,2012 年 2 月,<www.rfc-editor.org/info/rfc6532>。
- [LANGUAGE-TAGS]
-
Alvestrand, H.,“内容语言头”,RFC 3282,DOI 10.17487/RFC3282,2002 年 5 月,<www.rfc-editor.org/info/rfc3282>。
- [LOCATION]
-
Palme, J., Hopmann, A. 和 N. Shelness,“聚合文档(例如 HTML (MHTML))的 MIME 封装”,RFC 2557,DOI 10.17487/RFC2557,1999 年 3 月,<www.rfc-editor.org/info/rfc2557>。
- [MD5]
-
Myers, J. 和 M. Rose,“Content-MD5 头部字段”,RFC 1864,DOI 10.17487/RFC1864,1995 年 10 月,<www.rfc-editor.org/info/rfc1864>。
- [RFC3503]
-
Melnikov, A.,“Internet 消息访问协议(
IMAP
)的消息处理通知 (MDN) 配置文件”,RFC 3503,DOI 10.17487/RFC3503,2003 年 3 月,<www.rfc-editor.org/info/rfc3503>。
IMAP 扩展¶ ↑
- [QUOTA]
-
Melnikov, A.,“IMAP QUOTA 扩展”,RFC 9208,DOI 10.17487/RFC9208,2022 年 3 月,<www.rfc-editor.org/info/rfc9208>。
注意:取代 RFC-2087(1997 年 1 月)。Net::IMAP 尚未完全支持 RFC9208 的更新。
- [IDLE]
-
Leiba, B.,“IMAP4 IDLE 命令”,RFC 2177,DOI 10.17487/RFC2177,1997 年 6 月,<www.rfc-editor.org/info/rfc2177>。
- [NAMESPACE]
-
Gahrns, M. 和 C. Newman,“IMAP4 命名空间”,RFC 2342,DOI 10.17487/RFC2342,1998 年 5 月,<www.rfc-editor.org/info/rfc2342>。
- [ID]
-
Showalter, T.,“IMAP4 ID 扩展”,RFC 2971,DOI 10.17487/RFC2971,2000 年 10 月,<www.rfc-editor.org/info/rfc2971>。
- [BINARY]
-
Nerenberg, L.,“IMAP4 二进制内容扩展”,RFC 3516,DOI 10.17487/RFC3516,2003 年 4 月,<www.rfc-editor.org/info/rfc3516>。
- [ACL]
-
Melnikov, A.,“IMAP4 访问控制列表 (ACL) 扩展”,RFC 4314,DOI 10.17487/RFC4314,2005 年 12 月,<www.rfc-editor.org/info/rfc4314>。
- [UIDPLUS]
-
Crispin, M.,“Internet 消息访问协议 (IMAP) - UIDPLUS 扩展”,RFC 4315,DOI 10.17487/RFC4315,2005 年 12 月,<www.rfc-editor.org/info/rfc4315>。
- [SORT]
-
Crispin, M. 和 K. Murchison,“Internet 消息访问协议 - SORT 和 THREAD 扩展”,RFC 5256,DOI 10.17487/RFC5256,2008 年 6 月,<www.rfc-editor.org/info/rfc5256>。
- [THREAD]
-
Crispin, M. 和 K. Murchison,“Internet 消息访问协议 - SORT 和 THREAD 扩展”,RFC 5256,DOI 10.17487/RFC5256,2008 年 6 月,<www.rfc-editor.org/info/rfc5256>。
- [RFC5530]
-
Gulbrandsen, A.,“IMAP 响应代码”,RFC 5530,DOI 10.17487/RFC5530,2009 年 5 月,<www.rfc-editor.org/info/rfc5530>。
- [MOVE]
-
Gulbrandsen, A. 和 N. Freed, Ed.,“Internet 消息访问协议 (IMAP) - MOVE 扩展”,RFC 6851,DOI 10.17487/RFC6851,2013 年 1 月,<www.rfc-editor.org/info/rfc6851>。
- [UTF8=ACCEPT]
- [UTF8=ONLY]
-
Resnick, P., Ed., Newman, C., Ed. 和 S. Shen, Ed.,“IMAP 对 UTF-8 的支持”,RFC 6855,DOI 10.17487/RFC6855,2013 年 3 月,<www.rfc-editor.org/info/rfc6855>。
- [CONDSTORE]
- [QRESYNC]
-
Melnikov, A. 和 D. Cridland,“IMAP 扩展:快速标志更改重新同步 (CONDSTORE) 和快速邮箱重新同步 (QRESYNC)”,RFC 7162,DOI 10.17487/RFC7162,2014 年 5 月,<www.rfc-editor.org/info/rfc7162>。
- [OBJECTID]
-
Gondwana, B., Ed.,“对象标识符的 IMAP 扩展”,RFC 8474,DOI 10.17487/RFC8474,2018 年 9 月,<www.rfc-editor.org/info/rfc8474>。
- [PARTIAL]
-
Melnikov, A.,Achuthan, A.,Nagulakonda, V. 和 L. Alves,“用于分页搜索和获取的 IMAP PARTIAL 扩展”,RFC 9394,DOI 10.17487/RFC9394,2023 年 6 月,<www.rfc-editor.org/info/rfc9394>。
IANA 注册表¶ ↑
-
服务名称和传输协议端口号注册表:
imap
:tcp/143,imaps
:tcp/993
对于当前不支持的功能:¶ ↑
常量
- 数据
- ENABLE_ALIASES
支持的功能的别名,用于
enable
命令。- RESPONSES_DEPRECATION_MSG
- RETURN_START
- RETURN_WHOLE
- STRFDATE
IMAP4
date
的 strftime/strptime 格式,不包括可选的双引号。通过encode_date
和decode_date
方法使用。date = date-text / DQUOTE date-text DQUOTE date-text = date-day "-" date-month "-" date-year date-day = 1*2DIGIT ; Day of month date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" date-year = 4DIGIT
- STRFTIME
IMAP4
date-time
的 strftime/strptime 格式,包括双引号。请参阅encode_datetime
和decode_datetime
方法。date-time = DQUOTE date-day-fixed "-" date-month "-" date-year SP time SP zone DQUOTE 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-year = 4DIGIT time = 2DIGIT ":" 2DIGIT ":" 2DIGIT ; Hours minutes seconds 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".
请注意,Time.strptime
"%d"
灵活地解析空格或零填充。但是,双引号是不是可选的。- VERSION
属性
客户端配置。请参阅 Net::IMAP::Config
。
默认情况下,客户端的本地配置继承自全局 Net::IMAP.config
。
返回服务器的初始问候语,即 UntaggedResponse
。
此客户端连接到的主机名
此客户端连接到的端口
返回 TLS 尝试时 SSLSocket 使用的 SSLContext,即使 TLS 握手不成功。上下文对象将被冻结。
对于明文连接,返回 nil
。
返回发送到 ssl_ctx
set_params 的参数,当连接尝试使用 TLS 时(即使不成功)。
对于明文连接,返回 false
。
公共类方法
返回全局 Config
对象
# File net-imap-0.5.4/lib/net/imap.rb, line 755 def self.config; Config.global end
返回全局调试模式。
# File net-imap-0.5.4/lib/net/imap.rb, line 758 def self.debug; config.debug end
设置全局调试模式。
# File net-imap-0.5.4/lib/net/imap.rb, line 761 def self.debug=(val) config.debug = val end
将 string
解码为 IMAP
格式的“date”。
双引号是可选的。月份中的日期可以用零或空格填充。请参阅 STRFDATE
。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 90 def self.decode_date(string) string = string.delete_prefix('"').delete_suffix('"') Date.strptime(string, STRFDATE) end
将 string
解码为 IMAP4 格式的“date-time”。
注意:尽管双引号在 IMAP
语法中不是可选的,但 Net::IMAP
当前将“date-time”值解析为“带引号”的字符串,这将删除引号。为了对已解析为带引号字符串的字符串有用,此方法使双引号成为可选的。
请参阅 STRFTIME
。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 112 def self.decode_datetime(string) unless string.start_with?(?") && string.end_with?(?") string = '"%s"' % [string] end DateTime.strptime(string, STRFTIME) end
将 string
解码为 IMAP4 格式的“date-time”。
与 decode_datetime
相同,但返回 Time 而不是 DateTime。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 124 def self.decode_time(string) unless string.start_with?(?") && string.end_with?(?") string = '"%s"' % [string] end Time.strptime(string, STRFTIME) end
将字符串从修改后的 UTF-7 格式解码为 UTF-8 格式。
UTF-7 是一种 7 位 Unicode 编码 [UTF7]。IMAP
使用其稍作修改的版本来编码包含非 ASCII 字符的邮箱名称;请参阅 [IMAP] 第 5.1.3 节。
Net::IMAP
不会自动将邮箱名称编码和解码为 UTF-7 或从 UTF-7 解码。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 57 def self.decode_utf7(s) return s.gsub(/&([A-Za-z0-9+,]+)?-/n) { if base64 = $1 (base64.tr(",", "/") + "===").unpack1("m").encode(Encoding::UTF_8, Encoding::UTF_16BE) else "&" end } end
IMAP
连接的默认端口,端口号为 143
# File net-imap-0.5.4/lib/net/imap.rb, line 766 def self.default_port return PORT end
IMAPS 连接的默认端口,端口号为 993
# File net-imap-0.5.4/lib/net/imap.rb, line 771 def self.default_tls_port return SSL_PORT end
将 time
格式化为 IMAP4 日期。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 80 def self.encode_date(date) date.to_date.strftime STRFDATE end
将 time
格式化为 IMAP4 日期时间。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 98 def self.encode_datetime(time) time.to_datetime.strftime STRFTIME end
将字符串从 UTF-8 格式编码为修改后的 UTF-7 格式。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 68 def self.encode_utf7(s) return s.gsub(/(&)|[^\x20-\x7e]+/) { if $1 "&-" else base64 = [$&.encode(Encoding::UTF_16BE)].pack("m0") "&" + base64.delete("=").tr("/", ",") + "-" end }.force_encoding("ASCII-8BIT") end
- 已弃用
-
原始版本返回格式不正确的字符串。由
encode_datetime
或format_time
返回的字符串使用 “date-time” 的正确 IMAP4rev1 语法。
为向后兼容,暂时保留了这种无效格式。未来版本将更改此方法以返回正确的格式。
# File net-imap-0.5.4/lib/net/imap/data_encoding.rb, line 149 def self.format_datetime(time) warn("#{self}.format_datetime incorrectly formats IMAP date-time. " \ "Convert to #{self}.encode_datetime or #{self}.format_time instead.", uplevel: 1, category: :deprecated) time.strftime("%d-%b-%Y %H:%M %z") end
创建一个新的 Net::IMAP
对象,并将其连接到指定的 host
。
选项¶ ↑
接受以下选项
- port
-
端口号。当
ssl
为真值时,默认为 993,否则为 143。 - ssl
-
如果为
true
,则连接将使用 TLS,并使用 OpenSSL::SSL::SSLContext#set_params 设置的默认参数。如果ssl
是一个哈希,则会将其传递给 OpenSSL::SSL::SSLContext#set_params;键是 SSLContext 上的属性赋值方法的名称。例如- ca_file
-
包含 PEM 格式 CA 证书的文件的路径。
- ca_path
-
包含 PEM 格式 CA 证书的目录的路径。
- min_version
-
设置支持的 SSL/TLS 协议版本的下限。设置为
OpenSSL
常量,例如OpenSSL::SSL::TLS1_2_VERSION
。 - verify_mode
-
SSL 会话验证模式。有效的模式包括
OpenSSL::SSL::VERIFY_PEER
和OpenSSL::SSL::VERIFY_NONE
。
有关其他有效的 SSL 上下文参数,请参阅 OpenSSL::SSL::SSLContext。
有关已弃用的 SSL 参数,请参阅
DeprecatedClientOptions.new
。 - config
-
一个
Net::IMAP::Config
对象,用作config
的基础。默认情况下,使用全局Net::IMAP.config
。注意:
config
不会直接设置config
,而是设置用于继承的父级配置。每个客户端都会创建自己唯一的config
。所有其他关键字参数都会转发给
Net::IMAP::Config.new
,以初始化客户端的config
。例如- open_timeout
-
等待连接打开的秒数
- idle_response_timeout
-
等待接收 IDLE 响应的秒数
有关其他有效选项,请参阅
Net::IMAP::Config
。
示例¶ ↑
连接到 mail.example.com 上的明文端口 143 并接收服务器问候语
imap = Net::IMAP.new('mail.example.com', ssl: false) # => #<Net::IMAP:0x00007f79b0872bd0> imap.port => 143 imap.tls_verified? => false imap.greeting => name: ("OK" | "PREAUTH") => status status # => "OK" # The client is connected in the "Not Authenticated" state.
使用 TLS 连接到端口 993
imap = Net::IMAP.new('mail.example.com', ssl: true) # => #<Net::IMAP:0x00007f79b0872bd0> imap.port => 993 imap.tls_verified? => true imap.greeting => name: (/OK/i | /PREAUTH/i) => status case status in /OK/i # The client is connected in the "Not Authenticated" state. imap.authenticate("PLAIN", "joe_user", "joes_password") in /PREAUTH/i # The client is connected in the "Authenticated" state. end
使用先前的身份验证进行连接,例如使用 SSL 证书
ssl_ctx_params = { cert: OpenSSL::X509::Certificate.new(File.read("client.crt")), key: OpenSSL::PKey::EC.new(File.read('client.key')), extra_chain_cert: [ OpenSSL::X509::Certificate.new(File.read("intermediate.crt")), ], } imap = Net::IMAP.new('mail.example.com', ssl: ssl_ctx_params) imap.port => 993 imap.tls_verified? => true imap.greeting => name: "PREAUTH" # The client is connected in the "Authenticated" state.
异常¶ ↑
最常见的错误是
- Errno::ECONNREFUSED
-
连接被
host
或中间防火墙拒绝。 - Errno::ETIMEDOUT
-
连接超时(可能是由于中间防火墙丢弃了数据包)。
- Errno::ENETUNREACH
-
没有到达该网络的路由。
- SocketError
-
主机名未知或其他套接字错误。
Net::IMAP::ByeResponseError
-
已成功连接到主机,但主机立即道别。
# File net-imap-0.5.4/lib/net/imap.rb, line 923 def initialize(host, port: nil, ssl: nil, config: Config.global, **config_options) super() # Config options @host = host @config = Config.new(config, **config_options) @port = port || (ssl ? SSL_PORT : PORT) @ssl_ctx_params, @ssl_ctx = build_ssl_ctx(ssl) # Basic Client State @utf8_strings = false @debug_output_bol = true @exception = nil @greeting = nil @capabilities = nil # Client Protocol Receiver @parser = ResponseParser.new(config: @config) @responses = Hash.new {|h, k| h[k] = [] } @response_handlers = [] @receiver_thread = nil @receiver_thread_exception = nil @receiver_thread_terminating = false # Client Protocol Sender (including state for currently running commands) @tag_prefix = "RUBY" @tagno = 0 @tagged_responses = {} @tagged_response_arrival = new_cond @continued_command_tag = nil @continuation_request_arrival = new_cond @continuation_request_exception = nil @idle_done_cond = nil @logout_command_tag = nil # Connection @tls_verified = false @sock = tcp_socket(@host, @port) start_tls_session if ssl_ctx start_imap_connection end
私有类方法
委托给 Net::IMAP::StringPrep::SASLprep#saslprep
。
# File net-imap-0.5.4/lib/net/imap.rb, line 3572 def self.saslprep(string, **opts) Net::IMAP::StringPrep::SASLprep.saslprep(string, **opts) end
公共实例方法
添加响应处理程序。例如,要检测服务器何时发送新的 EXISTS 响应(通常表示向邮箱添加了新消息),请在选择邮箱后添加以下处理程序
imap.add_response_handler { |resp| if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS" puts "Mailbox now has #{resp.data} messages" end }
相关:remove_response_handler
、response_handlers
# File net-imap-0.5.4/lib/net/imap.rb, line 3081 def add_response_handler(handler = nil, &block) raise ArgumentError, "two Procs are passed" if handler && block synchronize do @response_handlers.push(block || handler) end end
发送 APPEND 命令 [IMAP4rev1 §6.3.11] 以将 message
追加到 mailbox
的末尾。可选的 flags
参数是初始传递给新消息的标志数组。可选的 date_time
参数指定要分配给新消息的创建时间;它默认为当前时间。
例如
imap.append("inbox", <<EOF.gsub(/\n/, "\r\n"), [:Seen], Time.now) Subject: hello From: [email protected] To: [email protected] hello world EOF
如果邮箱不存在(它不会自动创建),或者如果 flags、date_time 或 message 参数包含错误,则会引发 Net::IMAP::NoResponseError
。
功能¶ ↑
如果支持 UIDPLUS
[RFC4315] 并且目标支持持久 UID,则服务器的响应应包含带有 UIDPlusData
的 APPENDUID
响应代码。这将报告目标邮箱的 UIDVALIDITY 和追加消息的已分配 UID。
# File net-imap-0.5.4/lib/net/imap.rb, line 1856 def append(mailbox, message, flags = nil, date_time = nil) args = [] if flags args.push(flags) end args.push(date_time) if date_time args.push(Literal.new(message)) send_command("APPEND", mailbox, *args) end
返回服务器是否支持给定的 SASL
mechanism
用于 authenticate
命令。当 capabilities
包含 "AUTH=#{mechanism.to_s.upcase}"
时,支持 mechanism
。如果可用,将使用缓存的功能,而无需向服务器发送新的 capability
命令。
imap.capable? "AUTH=PLAIN" # => true imap.auth_capable? "PLAIN" # => true imap.auth_capable? "blurdybloop" # => false
相关:authenticate
、auth_mechanisms
、capable?
、capabilities
# File net-imap-0.5.4/lib/net/imap.rb, line 1067 def auth_capable?(mechanism) capable? "AUTH=#{mechanism}" end
返回服务器声明支持的 authenticate
机制。这些机制是从带有 AUTH=
前缀的 capabilities
中派生出来的。
当连接是明文还是使用 TLS 时,这可能会有所不同。大多数服务器会在连接经过身份验证后从 capabilities
中删除所有 AUTH=
机制。
imap = Net::IMAP.new(hostname, ssl: false) imap.capabilities # => ["IMAP4REV1", "LOGINDISABLED"] imap.auth_mechanisms # => [] imap.starttls imap.capabilities # => ["IMAP4REV1", "AUTH=PLAIN", "AUTH=XOAUTH2", # "AUTH=OAUTHBEARER"] imap.auth_mechanisms # => ["PLAIN", "XOAUTH2", "OAUTHBEARER"] imap.authenticate("XOAUTH2", username, oauth2_access_token) imap.auth_mechanisms # => []
相关:authenticate
、auth_capable?
、capabilities
# File net-imap-0.5.4/lib/net/imap.rb, line 1050 def auth_mechanisms capabilities .grep(/\AAUTH=/i) .map { _1.delete_prefix("AUTH=") } end
发送 AUTHENTICATE 命令 [IMAP4rev1 §6.2.2] 以对客户端进行身份验证。如果成功,连接将进入 “已身份验证” 状态。
mechanism
是要使用的 SASL 身份验证机制的名称。
sasl_ir
允许或禁止发送 “初始响应”(请参阅下面的 SASL-IR
功能)。默认为 config
中 sasl_ir 的值,默认为 true
。
registry
kwarg 可用于从自定义注册表中选择机制实现。请参阅 SASL.authenticator
和 SASL::Authenticators
。
所有其他参数都会转发到请求的机制的已注册 SASL
身份验证器。必须查阅每种机制的文档以了解其特定参数。
相关:login
、starttls
、auth_capable?
、auth_mechanisms
机制¶ ↑
每个机制都有不同的属性和要求。请查阅您正在使用的特定机制的文档。
ANONYMOUS (匿名)
-
允许用户在不进行身份验证或不公开身份的情况下访问公共服务或资源。
EXTERNAL (外部)
-
使用已建立的凭据(如 TLS 证书或 IPsec)进行身份验证。
OAUTHBEARER
-
使用 OAuth2 Bearer 令牌登录。这是将 OAuth2 与 SASL 一起使用的标准机制,但尚未像
XOAUTH2
那样广泛部署。 PLAIN (明文)
-
请参阅 PlainAuthenticator。
使用明文用户名和密码登录。
SCRAM-SHA-1
SCRAM-SHA-256
-
请参阅 ScramAuthenticator。
通过用户名和密码登录。密码不会发送到服务器,而是用于加盐质询/响应交换。
Net::IMAP::SASL
直接支持SCRAM-SHA-1
和SCRAM-SHA-256
。如果 OpenSSL::Digest 支持摘要算法,则可以轻松为任何其他SCRAM-*
机制添加新的身份验证器。 XOAUTH2
-
请参阅 XOAuth2Authenticator。
使用用户名和 OAuth2 访问令牌登录。非标准且已被
OAUTHBEARER
废弃,但被广泛支持。
有关所有 SASL
机制及其规范的列表,请参阅 SASL 机制注册表。要注册新的身份验证器,请参阅 Authenticators
。
已弃用的机制¶ ↑
应避免使用过时的机制,但为了向后兼容仍然可用。请参阅 Net::IMAP::SASL
中已弃用的机制。使用已弃用的机制会打印警告。
功能¶ ↑
"AUTH=#{mechanism}"
功能表示服务器支持的机制。在使用特定机制之前,请使用 auth_capable?
或 auth_mechanisms
来检查是否支持。
if imap.auth_capable? "XOAUTH2" imap.authenticate "XOAUTH2", username, oauth2_access_token elsif imap.auth_capable? "PLAIN" imap.authenticate "PLAIN", username, password elsif !imap.capability? "LOGINDISABLED" imap.login username, password else raise "No acceptable authentication mechanism is available" end
尽管服务器应列出所有支持的 SASL 机制,但它们可能允许使用未列出的 mechanism
进行身份验证。
如果支持 [SASL-IR] 并且存在相应的 "AUTH=#{mechanism}"
功能,则可以将“初始响应”作为 AUTHENTICATE
命令的参数发送,从而节省一次往返。 SASL
交换允许服务器质询和客户端响应,但许多机制期望客户端首先“响应”。初始响应仅会为“客户端优先”机制发送。
服务器功能可能会在 starttls
、login
和 authenticate
之后更改。当此方法完成时,之前缓存的 capabilities
将被清除。如果 TaggedResponse
到 authenticate
包含更新的功能,则它们将被缓存。
# File net-imap-0.5.4/lib/net/imap.rb, line 1350 def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback) sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback) .tap { @capabilities = capabilities_from_resp_code _1 } end
返回服务器功能。如果可用,则使用缓存的功能,而无需向服务器发送新的 capability
命令。
为了确保不区分大小写的比较,可以使用 capable?
。
注意: 大多数 Net::IMAP 方法当前不会根据服务器的 #capabilities 公告修改其行为。
有关 IMAP 功能的更多信息,请参阅 Net::IMAP
中的功能。
相关:capable?
, auth_capable?
, auth_mechanisms
, capability
, enable
# File net-imap-0.5.4/lib/net/imap.rb, line 1026 def capabilities @capabilities || capability end
返回是否已缓存功能。如果为 true,则 capable?
和 capabilities
不需要向服务器发送 capability
命令。
有关 IMAP 功能的更多信息,请参阅 Net::IMAP
中的功能。
相关:capable?
, capability
, clear_cached_capabilities
# File net-imap-0.5.4/lib/net/imap.rb, line 1077 def capabilities_cached? !!@capabilities end
发送 CAPABILITY 命令 [IMAP4rev1 §6.1.1] 并返回服务器支持的功能数组。结果存储起来供 capable?
和 capabilities
使用。
注意: 大多数 Net::IMAP 方法当前不会根据服务器的 #capabilities 公告修改其行为。
Net::IMAP
会根据 IMAP4rev2 §6.1.1、§6.2 和 §7.1 中的要求和建议自动存储和丢弃功能数据。使用 capable?
、auth_capable?
或 capabilities
访问此缓存并避免不必要地发送 capability
命令。
有关 IMAP 功能的更多信息,请参阅 Net::IMAP
中的功能。
相关:capable?
, auth_capable?
, capability
, enable
# File net-imap-0.5.4/lib/net/imap.rb, line 1115 def capability synchronize do send_command("CAPABILITY") @capabilities = clear_responses("CAPABILITY").last.freeze end end
返回服务器是否支持给定的 capability
。如果可用,则使用缓存的 capabilities
,而无需向服务器发送新的 capability
命令。
注意: 大多数 Net::IMAP 方法当前不会根据服务器的 #capabilities 公告修改其行为。
有关 IMAP 功能的更多信息,请参阅 Net::IMAP
中的功能。
相关:auth_capable?
, capabilities
, capability
, enable
# File net-imap-0.5.4/lib/net/imap.rb, line 1012 def capable?(capability) capabilities.include? capability.to_s.upcase end
发送 CHECK 命令 [IMAP4rev1 §6.4.1] 以请求当前选定邮箱的检查点。这将执行特定于实现的内务处理;例如,协调邮箱的内存和磁盘状态。
# File net-imap-0.5.4/lib/net/imap.rb, line 1872 def check send_command("CHECK") end
清除 Net::IMAP
客户端记住的功能。这会强制在下次调用 capabilities
查询方法时发送 capability
命令。
当 Net::IMAP
的缓存功能可能发生更改时,会自动丢弃这些缓存的功能。显式调用此方法应该对于行为良好的服务器是不必要的。
相关:capable?
, capability
, capabilities_cached?
# File net-imap-0.5.4/lib/net/imap.rb, line 1090 def clear_cached_capabilities synchronize do clear_responses("CAPABILITY") @capabilities = nil end end
清除并返回未处理的 responses
哈希或单个响应 type
的未处理响应数组。
清除响应与其他线程同步。锁定在返回之前释放。
相关:extract_responses
, responses
, response_handlers
# File net-imap-0.5.4/lib/net/imap.rb, line 3014 def clear_responses(type = nil) synchronize { if type @responses.delete(type) || [] else @responses.dup.transform_values(&:freeze) .tap { _1.default = [].freeze } .tap { @responses.clear } end } .freeze end
发送 CLOSE 命令 [IMAP4rev1 §6.4.2] 以关闭当前选定的邮箱。CLOSE 命令会从邮箱中永久删除所有设置了 \Deleted
标志的消息。
相关:unselect
# File net-imap-0.5.4/lib/net/imap.rb, line 1882 def close send_command("CLOSE") end
发送 COPY 命令 [IMAP4rev1 §6.4.7] 以将指定的消息复制到指定目标 mailbox
的末尾。 set
参数是一个数字、一个数字数组或一个 Range 对象。该数字是一个消息序列号。
相关:uid_copy
功能¶ ↑
如果支持 UIDPLUS
[RFC4315],则服务器的响应应包含带有 UIDPlusData
的 COPYUID
响应代码。这将报告目标邮箱的 UIDVALIDITY、源消息的 UID 集以及移动消息的已分配 UID 集。
# File net-imap-0.5.4/lib/net/imap.rb, line 2578 def copy(set, mailbox) copy_internal("COPY", set, mailbox) end
发送 CREATE 命令 [IMAP4rev1 §6.3.3] 以创建新的 mailbox
。
如果无法创建具有该名称的邮箱,则会引发 Net::IMAP::NoResponseError
。
# File net-imap-0.5.4/lib/net/imap.rb, line 1456 def create(mailbox) send_command("CREATE", mailbox) end
发送 DELETE 命令 [IMAP4rev1 §6.3.4] 以删除 mailbox
。
如果无法删除具有该名称的邮箱(因为它不存在或客户端没有删除权限),则会引发 Net::IMAP::NoResponseError
。
# File net-imap-0.5.4/lib/net/imap.rb, line 1468 def delete(mailbox) send_command("DELETE", mailbox) end
断开与服务器的连接。
# File net-imap-0.5.4/lib/net/imap.rb, line 973 def disconnect return if disconnected? begin begin # try to call SSL::SSLSocket#io. @sock.io.shutdown rescue NoMethodError # @sock is not an SSL::SSLSocket. @sock.shutdown end rescue Errno::ENOTCONN # ignore `Errno::ENOTCONN: Socket is not connected' on some platforms. rescue Exception => e @receiver_thread.raise(e) end @receiver_thread.join synchronize do @sock.close end raise e if e end
如果与服务器断开连接,则返回 true。
相关:logout
, disconnect
# File net-imap-0.5.4/lib/net/imap.rb, line 998 def disconnected? return @sock.closed? end
发送 ENABLE 命令 [RFC5161 §3.2] [IMAP4rev2 §6.3.1] 以启用指定的服务器 capabilities
。每个功能可以是数组、字符串或符号。返回已启用的功能列表。
ENABLE
命令仅在已验证状态下有效,在选择任何邮箱之前。
相关:capable?
, capabilities
, capability
功能¶ ↑
服务器的功能必须包括 ENABLE
[RFC5161] 或 IMAP4REV2
[RFC9051]。
此外,服务器功能必须包括与每个启用的扩展匹配的功能(通常与启用的扩展同名)。可以启用以下功能
CONDSTORE
[RFC7162]-
更新各种命令以返回
CONDSTORE
扩展响应。无需显式启用CONDSTORE
- 使用扩展定义的任何命令参数都会隐式启用它。请参阅 [RFC7162 §3.1]。 :utf8
—"UTF8=ACCEPT"
的别名-
在未来的版本中,
enable(:utf8)
将启用"UTF8=ACCEPT"
或"IMAP4rev2"
,具体取决于服务器功能。 "UTF8=ACCEPT"
[RFC6855]-
服务器的功能必须包括
UTF8=ACCEPT
或UTF8=ONLY
。这允许服务器发送以 UTF-8 编码的字符串,这些字符串可能需要使用 7 位编码,例如用于邮箱名称的 修改后的 UTF-7,或者用于消息头的 RFC2047 编码字。
注意: 未来的更新可能会略微不同的设置字符串编码,例如:当未启用 UTF-8 时使用 “US-ASCII”,启用时使用 “UTF-8”。目前,以 “quoted” 或 “text” 发送的字符串的编码将始终为 “UTF-8”,即使只使用了 ASCII 字符(例如,“Subject: Agenda”)。并且目前,服务器发送的字符串 “literals” 将始终具有 “ASCII-8BIT”(二进制)编码,即使它们通常包含 UTF-8 数据(如果它们是文本的话)。
"UTF8=ONLY"
[RFC6855]-
报告
UTF8=ONLY
功能的服务器要求客户端在选择任何邮箱之前enable("UTF8=ACCEPT")
。为方便起见,enable("UTF8=ONLY")
被别名为enable("UTF8=ACCEPT")
。
不支持的功能¶ ↑
注意: 一些使用 ENABLE 的扩展允许服务器发送 Net::IMAP
无法解析的语法,这可能会引发异常并断开连接。某些扩展可能有效,但支持可能不完整、未经测试或处于实验阶段。
在某个功能被记录为支持之前,启用它可能会导致未记录的行为,并且未来的版本可能会在没有警告或弃用的情况下更新为不兼容的行为。
建议谨慎使用。
# File net-imap-0.5.4/lib/net/imap.rb, line 2789 def enable(*capabilities) capabilities = capabilities .flatten .map {|e| ENABLE_ALIASES[e] || e } .uniq .join(' ') synchronize do send_command("ENABLE #{capabilities}") result = clear_responses("ENABLED").last || [] @utf8_strings ||= result.include? "UTF8=ACCEPT" @utf8_strings ||= result.include? "IMAP4REV2" result end end
发送 EXAMINE 命令 [IMAP4rev1 §6.3.2] 以选择一个 mailbox
,以便可以访问该 mailbox
中的消息。行为与 select
相同,只是选定的 mailbox
被标识为只读。
如果邮箱不存在或因某种原因无法检查,则会引发 Net::IMAP::NoResponseError
。
相关:select
# File net-imap-0.5.4/lib/net/imap.rb, line 1440 def examine(mailbox, condstore: false) args = ["EXAMINE", mailbox] args << ["CONDSTORE"] if condstore synchronize do @responses.clear send_command(*args) end end
发送一个 EXPUNGE 命令 [IMAP4rev1 §6.4.3],以永久删除当前选定的邮箱中所有带有 \Deleted
标志的消息。
返回已清除消息的序列号数组,或者(当启用相应的功能时)返回已清除 UID 的 VanishedData
。先前未处理的 EXPUNGE
或 VANISHED
响应将与此命令的直接响应合并。VANISHED (EARLIER)
响应将不被合并。
当没有消息被清除时,无论启用了哪些扩展,都将返回一个空数组。在未来的版本中,可能会返回一个空的 VanishedData
,具体取决于当前启用的扩展。
相关:uid_expunge
功能¶ ↑
当启用 QRESYNC 或 UIDONLY 时,expunge
返回 VanishedData
,其中包含 UID——而不是消息序列号。
# File net-imap-0.5.4/lib/net/imap.rb, line 1928 def expunge expunge_internal("EXPUNGE") end
为单个响应 type
生成所有未处理的 responses
。删除并返回块返回真值的响应。
提取响应与其它线程同步。锁在返回之前释放。
# File net-imap-0.5.4/lib/net/imap.rb, line 3038 def extract_responses(type) type = String.try_convert(type) or raise ArgumentError, "type must be a string" raise ArgumentError, "must provide a block" unless block_given? extracted = [] responses(type) do |all| all.reject! do |response| extracted << response if yield response end end extracted end
发送一个 FETCH 命令 [IMAP4rev1 §6.4.5] 以检索与邮箱中消息关联的数据。
set
是要获取的消息序列号,可以是 SequenceSet[…] 的任何有效输入。(对于 UID,请改用 uid_fetch
。)
attr
是要获取的属性列表;有关有效属性列表,请参阅 FetchData
的文档。
changedsince
是一个可选的整数 mod-sequence。它将结果限制为 mod-sequence 大于 changedsince
的消息。
返回值是 FetchData
的数组。
例如:¶ ↑
p imap.fetch(6..8, "UID") #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\ #<Net::IMAP::FetchData seqno=7, attr={"UID"=>99}>, \\ #<Net::IMAP::FetchData seqno=8, attr={"UID"=>100}>] p imap.fetch(6, "BODY[HEADER.FIELDS (SUBJECT)]") #=> [#<Net::IMAP::FetchData seqno=6, attr={"BODY[HEADER.FIELDS (SUBJECT)]"=>"Subject: test\r\n\r\n"}>] data = imap.uid_fetch(98, ["RFC822.SIZE", "INTERNALDATE"])[0] p data.seqno #=> 6 p data.attr["RFC822.SIZE"] #=> 611 p data.attr["INTERNALDATE"] #=> "12-Oct-2000 22:40:59 +0900" p data.attr["UID"] #=> 98
功能¶ ↑
许多扩展定义了新的消息 attr
名称。有关支持的扩展字段列表,请参阅 FetchData
。
服务器的功能必须包含 CONDSTORE
[RFC7162] 才能使用 changedsince
参数。使用 changedsince
会隐式启用 CONDSTORE
扩展。
# File net-imap-0.5.4/lib/net/imap.rb, line 2437 def fetch(...) fetch_internal("FETCH", ...) end
发送一个 GETACL 命令 [RFC4314 §3.3] 以及指定的 mailbox
。如果此邮箱存在,将返回包含 MailboxACLItem
对象的数组。
相关:setacl
, MailboxACLItem
功能¶ ↑
服务器的功能必须包含 ACL
[RFC4314]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1736 def getacl(mailbox) synchronize do send_command("GETACL", mailbox) clear_responses("ACL").last end end
发送一个 GETQUOTA 命令 [RFC2087 §4.2] 以及指定的 mailbox
。如果此邮箱存在,则返回一个包含 MailboxQuota
对象的数组。此命令通常只对服务器管理员可用。
相关:getquotaroot
, setquota
, MailboxQuota
功能¶ ↑
服务器的功能必须包含 QUOTA
[RFC2087]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1680 def getquota(mailbox) synchronize do send_command("GETQUOTA", mailbox) clear_responses("QUOTA") end end
发送一个 GETQUOTAROOT 命令 [RFC2087 §4.3] 以及指定的 mailbox
。此命令通常对管理员和用户都可用。如果此邮箱存在,则返回一个包含 MailboxQuotaRoot
和 MailboxQuota
类型对象的数组。
相关:getquota
, setquota
, MailboxQuotaRoot
, MailboxQuota
功能¶ ↑
服务器的功能必须包含 QUOTA
[RFC2087]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1659 def getquotaroot(mailbox) synchronize do send_command("GETQUOTAROOT", mailbox) result = [] result.concat(clear_responses("QUOTAROOT")) result.concat(clear_responses("QUOTA")) return result end end
发送一个 ID 命令 [RFC2971 §3.1] 并返回服务器响应的哈希值,如果服务器不标识自身,则返回 nil。
请注意,用户应首先检查服务器是否支持 ID 功能。例如
if capable?(:ID) id = imap.id( name: "my IMAP client (ruby)", version: MyIMAP::VERSION, "support-url": "mailto:[email protected]", os: RbConfig::CONFIG["host_os"], ) end
有关字段定义,请参阅 [ID]。
功能¶ ↑
服务器的功能必须包含 ID
[RFC2971]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1144 def id(client_id=nil) synchronize do send_command("ID", ClientID.new(client_id)) clear_responses("ID").last end end
发送一个 IDLE 命令 [RFC2177 §3] [IMAP4rev2 §6.3.13],该命令等待新消息或已删除消息的通知。在 IDLE 期间生成服务器的响应。
使用 idle_done
离开 IDLE。
如果给定 timeout
,则此方法将在经过 timeout
秒后返回。timeout
可用于保持活动状态。例如,以下代码每 60 秒检查一次连接。
loop do imap.idle(60) do |response| do_something_with(response) imap.idle_done if some_condition?(response) end end
返回服务器的响应,指示 IDLE 状态已结束。如果在 config.idle_response_timeout 秒内服务器未响应 idle_done
,则返回 nil
。
功能¶ ↑
服务器的功能必须包含 IDLE
[RFC2177]。
# File net-imap-0.5.4/lib/net/imap.rb, line 2833 def idle(timeout = nil, &response_handler) raise LocalJumpError, "no block given" unless response_handler response = nil synchronize do tag = Thread.current[:net_imap_tag] = generate_tag put_string("#{tag} IDLE#{CRLF}") begin add_response_handler(&response_handler) @idle_done_cond = new_cond @idle_done_cond.wait(timeout) @idle_done_cond = nil if @receiver_thread_terminating raise @exception || Net::IMAP::Error.new("connection closed") end ensure unless @receiver_thread_terminating remove_response_handler(response_handler) put_string("DONE#{CRLF}") response = get_tagged_response(tag, "IDLE", idle_response_timeout) end end end return response end
离开 IDLE,允许 idle
返回。
如果服务器在 config.idle_response_timeout 秒内没有响应,idle
将返回 nil
。
相关:idle
# File net-imap-0.5.4/lib/net/imap.rb, line 2869 def idle_done synchronize do if @idle_done_cond.nil? raise Net::IMAP::Error, "not during IDLE" end @idle_done_cond.signal end end
等待接收 IDLE 响应的秒数。
# File net-imap-0.5.4/lib/net/imap.rb, line 796 def idle_response_timeout; config.idle_response_timeout end
发送一个 LIST 命令 [IMAP4rev1 §6.3.8] 并返回客户端可用的所有名称的完整集合中的名称子集。refname
提供上下文(例如,基于目录的邮箱层次结构中的基本目录)。mailbox
指定该上下文中指定的邮箱或(通过通配符)邮箱。mailbox
中可以使用两个通配符:"*"
,它匹配所有字符,包括层次结构分隔符(例如,在 UNIX 主机上的基于目录的邮箱层次结构中的“/”);和 "%"
,它匹配所有字符,不包括层次结构分隔符。
如果 refname
为空,则直接使用 mailbox
来确定要匹配哪些邮箱。如果 mailbox
为空,则返回 refname
的根名称和层次结构分隔符。
返回值是一个 MailboxList
数组。
相关:lsub
, MailboxList
例如:¶ ↑
imap.create("foo/bar") imap.create("foo/baz") p imap.list("", "foo/%") #=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, \\ #<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, \\ #<Net::IMAP::MailboxList attr=[:Noinferiors], delim="/", name="foo/baz">]
# File net-imap-0.5.4/lib/net/imap.rb, line 1540 def list(refname, mailbox) synchronize do send_command("LIST", refname, mailbox) clear_responses("LIST") end end
发送一个 LOGIN 命令 [IMAP4rev1 §6.2.3] 来标识客户端,并携带明文 password
以验证此 user
的身份。如果成功,连接将进入“已验证”状态。
使用 authenticate
应该优先于 login
。LOGIN 命令与使用“LOGIN” mechanism
的 authenticate
不同。
如果身份验证失败,则会引发 Net::IMAP::NoResponseError
异常。
相关内容:authenticate
,starttls
功能¶ ↑
当服务器通告 LOGINDISABLED
功能时,IMAP
客户端不得调用 login
。默认情况下,当存在该功能时,Net::IMAP
将引发 LoginDisabledError
异常。请参阅 Config#enforce_logindisabled
。
在 starttls
,login
和 authenticate
后,服务器的功能可能会更改。在此方法完成后,必须使缓存的功能失效。login
的 TaggedResponse
可能在其 ResponseCode
中包含更新后的功能。
# File net-imap-0.5.4/lib/net/imap.rb, line 1381 def login(user, password) if enforce_logindisabled? && capability?("LOGINDISABLED") raise LoginDisabledError end send_command("LOGIN", user, password) .tap { @capabilities = capabilities_from_resp_code _1 } end
发送一个 LOGOUT 命令 [IMAP4rev1 §6.1.3],通知服务器客户端已完成连接。
相关内容:disconnect
,logout!
# File net-imap-0.5.4/lib/net/imap.rb, line 1172 def logout send_command("LOGOUT") end
调用 logout
,然后在收到 LOGOUT
的 TaggedResponse
后,调用 disconnect
。返回来自 LOGOUT
的 TaggedResponse
。当客户端已断开连接时,返回 nil
,这与引发异常的 logout
不同。
如果 logout
引发 StandardError 异常,将打印警告,但不会重新引发该异常。
这在必须断开连接的情况下非常有用,例如出于安全考虑或测试后。如果需要处理注销错误,请改用 logout
和 disconnect
。
相关:logout
, disconnect
# File net-imap-0.5.4/lib/net/imap.rb, line 1189 def logout! logout unless disconnected? rescue => ex warn "%s during <Net::IMAP %s:%s> logout!: %s" % [ ex.class, host, port, ex ] ensure disconnect end
发送一个 LSUB 命令 [IMAP4rev1 §6.3.9],并从用户声明为“活动”或“已订阅”的名称集合中返回一个名称子集。refname
和 mailbox
的解释与 list
相同。
返回值是一个 MailboxList
对象数组。
相关内容:subscribe
,unsubscribe
,list
,MailboxList
# File net-imap-0.5.4/lib/net/imap.rb, line 1751 def lsub(refname, mailbox) synchronize do send_command("LSUB", refname, mailbox) clear_responses("LSUB") end end
发送一个 MOVE 命令 [RFC6851 §3.1] [IMAP4rev2 §6.4.8],将指定的消息移动到指定目标 mailbox
的末尾。set
参数是一个数字、数字数组或 Range 对象。该数字是消息序列号。
相关内容:uid_move
功能¶ ↑
服务器的功能必须包含 MOVE
[RFC6851]。
如果支持 UIDPLUS
[RFC4315],则服务器的响应应包含带有 UIDPlusData
的 COPYUID
响应代码。这将报告目标邮箱的 UIDVALIDITY、源消息的 UID 集以及移动消息的已分配 UID 集。
# File net-imap-0.5.4/lib/net/imap.rb, line 2614 def move(set, mailbox) copy_internal("MOVE", set, mailbox) end
发送一个 NAMESPACE 命令 [RFC2342 §5],并返回可用的命名空间。NAMESPACE 命令允许客户端发现服务器用于个人邮箱、其他用户的邮箱和共享邮箱的命名空间前缀。
返回值是一个 Namespaces
对象,该对象具有 personal
、other
和 shared
字段,每个字段都是一个 Namespace
对象数组。当服务器响应 nil
时,这些数组将为空。
许多 IMAP 服务器配置的默认个人命名空间为 ("" "/")
:没有前缀和 “/
” 层级分隔符。在那种常见情况下,朴素的客户端可能在命名邮箱时不会遇到任何问题。但是,许多服务器配置的默认个人命名空间为例如 ("INBOX." ".")
,将所有个人文件夹放在 INBOX 下,并以 “.
” 作为层级分隔符。如果客户端不检查这一点,而是天真地假设它可以为所有服务器使用相同的文件夹名称,则文件夹创建(以及列表、移动等)可能会导致错误。
来自 RFC2342
尽管通常服务器只支持一个个人命名空间和一个其他用户的命名空间,但在某些情况下,可能存在多个这些命名空间,客户端必须为它们做好准备。如果配置客户端时需要创建某个邮箱,则在某些情况下,不清楚应在哪个个人命名空间中创建邮箱。在这些情况下,客户端应让用户选择在哪个命名空间中创建邮箱。
相关内容:list
,Namespaces
,Namespace
例如:¶ ↑
if capable?("NAMESPACE") namespaces = imap.namespace if namespace = namespaces.personal.first prefix = namespace.prefix # e.g. "" or "INBOX." delim = namespace.delim # e.g. "/" or "." # personal folders should use the prefix and delimiter imap.create(prefix + "foo") imap.create(prefix + "bar") imap.create(prefix + %w[path to my folder].join(delim)) end end
功能¶ ↑
服务器的功能必须包含 NAMESPACE
[RFC2342]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1597 def namespace synchronize do send_command("NAMESPACE") clear_responses("NAMESPACE").last end end
向服务器发送一个 NOOP 命令 [IMAP4rev1 §6.1.2]。
这允许服务器发送未经请求的未标记的 EXPUNGE responses
,但不执行任何客户端请求。允许 IMAP 服务器随时发送未经请求的未标记响应,但 EXPUNGE
除外。
-
EXPUNGE
只能在命令正在进行时发送。 -
可以在
uid_fetch
、uid_store
或uid_search
期间发送EXPUNGE
。
# File net-imap-0.5.4/lib/net/imap.rb, line 1163 def noop send_command("NOOP") end
等待连接打开的秒数。如果 IMAP
对象无法在此时间内打开连接,则会引发 Net::OpenTimeout 异常。默认值为 30 秒。
# File net-imap-0.5.4/lib/net/imap.rb, line 793 def open_timeout; config.open_timeout end
删除响应处理程序。
相关内容:add_response_handler
,response_handlers
# File net-imap-0.5.4/lib/net/imap.rb, line 3091 def remove_response_handler(handler) synchronize do @response_handlers.delete(handler) end end
发送一个 RENAME 命令 [IMAP4rev1 §6.3.5],将 mailbox
的名称更改为 newname
。
如果由于任何原因无法将名为 mailbox
的邮箱重命名为 newname
,例如,因为 mailbox
不存在,或者因为已经存在名为 newname
的邮箱,则会引发 Net::IMAP::NoResponseError
异常。
# File net-imap-0.5.4/lib/net/imap.rb, line 1481 def rename(mailbox, newname) send_command("RENAME", mailbox, newname) end
返回所有响应处理程序,包括由命令内部添加的响应处理程序。每个响应处理程序都将使用每个新的 UntaggedResponse
、TaggedResponse
和 ContinuationRequest
来调用。
响应处理程序在接收器线程内的互斥锁中调用。无法处理新的响应,来自其他线程的命令必须等到所有 response_handlers
返回后才能继续。异常将关闭接收器线程并关闭连接。
为了线程安全,返回的数组是内部数组的冻结副本。
相关内容:add_response_handler
,remove_response_handler
# File net-imap-0.5.4/lib/net/imap.rb, line 3064 def response_handlers synchronize { @response_handlers.clone.freeze } end
生成或返回未处理的服务器响应。未处理的响应存储在哈希中,其中 UntaggedResponse#data
的数组按 UntaggedResponse#name
键控,而 非-nil
未标记的 ResponseCode#data
按 ResponseCode#name
键控。
当给定代码块时,生成未处理的响应并返回代码块的结果。如果没有代码块,则返回未处理的响应。
- 使用
type
-
仅生成或返回该
type
的响应数组。当未给定代码块时,返回的数组是冻结的副本。 - 没有
type
-
生成或返回整个响应哈希。
当未给定代码块时,其行为由
Config#responses_without_block
确定。:silence_deprecation_warning
(原始行为)-
返回可变的响应哈希(没有任何警告)。这不是线程安全的。
:warn
(自v0.5
以来的默认值)-
打印警告并返回可变响应哈希。这并非线程安全。
:frozen_dup
(计划在v0.6
中默认为此项)-
返回未处理响应哈希的冻结副本,其中包含冻结的数组值。
:raise
-
引发带有弃用警告的
ArgumentError
。
例如
imap.select("inbox") p imap.responses("EXISTS").last #=> 2 p imap.responses("UIDNEXT", &:last) #=> 123456 p imap.responses("UIDVALIDITY", &:last) #=> 968263756 p imap.responses {|responses| { exists: responses.delete("EXISTS").last, uidnext: responses.delete("UIDNEXT").last, uidvalidity: responses.delete("UIDVALIDITY").last, } } #=> {:exists=>2, :uidnext=>123456, :uidvalidity=>968263756} # "EXISTS", "UIDNEXT", and "UIDVALIDITY" have been removed: p imap.responses(&:keys) #=> ["FLAGS", "OK", "PERMANENTFLAGS", "RECENT", "HIGHESTMODSEQ"]
相关:extract_responses
, clear_responses
, response_handlers
, greeting
线程安全¶ ↑
注意: 对响应哈希的访问是同步的,以确保线程安全。接收线程和
response_handlers
在代码块完成之前无法处理新的响应。在代码块之外访问响应哈希或其响应类型数组是不安全的。它们可以在代码块内安全地更新。请考虑使用clear_responses
或extract_responses
代替。
Net::IMAP
将在调用命令的线程和接收线程中添加和删除响应哈希及其数组值中的响应,但不会在将响应添加到响应哈希后修改任何响应。
清除响应¶ ↑
先前未处理的响应会在使用 select
或 examine
进入邮箱之前自动清除。长时间存在的连接可能会收到许多未处理的服务器响应,必须对其进行修剪,否则它们将持续消耗更多内存。在代码块内更新或清除响应哈希或数组,或使用 extract_responses
、clear_responses
或 add_response_handler
删除响应。
缺少响应¶ ↑
仅存储非 nil
数据。许多重要的响应代码本身没有数据,但被用作附加到的 ResponseText
对象的“标签”。ResponseText
将可通过其响应类型访问:“OK
”、“NO
”、“BAD
”、“BYE
”或“PREAUTH
”。
TaggedResponse#data
不会保存到 responses
中,也不会保存标记响应上的任何 ResponseCode#data
。尽管某些命令方法会直接返回 TaggedResponse
,但必须使用 add_response_handler
来处理所有响应代码。
# File net-imap-0.5.4/lib/net/imap.rb, line 2980 def responses(type = nil) if block_given? synchronize { yield(type ? @responses[type.to_s.upcase] : @responses) } elsif type synchronize { @responses[type.to_s.upcase].dup.freeze } else case config.responses_without_block when :raise raise ArgumentError, RESPONSES_DEPRECATION_MSG when :warn warn(RESPONSES_DEPRECATION_MSG, uplevel: 1, category: :deprecated) when :frozen_dup synchronize { responses = @responses.transform_values(&:freeze) responses.default_proc = nil responses.default = [].freeze return responses.freeze } end @responses end end
发送 SEARCH 命令 [IMAP4rev1 §6.4.4],以在邮箱中搜索与给定搜索 criteria
匹配的消息,并返回 SearchResult
或 ESearchResult
。SearchResult
继承自 Array(为了向后兼容),但在启用 CONDSTORE
功能时添加 SearchResult#modseq
。ESearchResult
还实现了 #to_a,以便与 SearchResult
兼容。
criteria
是一个或多个搜索键及其参数,可以作为数组或字符串提供。请参见下面的“参数转换”和 “搜索条件”。
return
选项控制返回有关与搜索 criteria
匹配的消息的哪种信息。指定 return
应该强制服务器返回 ESearchResult
而不是 SearchResult
,但某些服务器不遵守此要求。需要扩展的搜索功能,例如 ESEARCH
或 IMAP4rev2
。请参见下面的“参数转换”和 “支持的返回选项”。
charset
是搜索 criteria
中字符串使用的注册字符集的名称。当未指定 charset
时,将假定为 "US-ASCII"
或 "UTF-8"
,具体取决于服务器的功能。
注意: 返回选项和字符集可以作为 criteria
的一部分发送。当返回选项或字符集嵌入到 criteria
中时,请勿使用 return
或 charset
参数。
相关:uid_search
例如:¶ ↑
imap.search(["SUBJECT", "hello", "NOT", "SEEN"]) #=> [1, 6, 7, 8]
以下假设服务器支持 ESEARCH
和 CONDSTORE
result = imap.uid_search(["UID", 12345.., "MODSEQ", 620_162_338], return: %w(all count min max)) # => #<data Net::IMAP::ESearchResult tag="RUBY0123", uid=true, # data=[["ALL", Net::IMAP::SequenceSet["12346:12349,22222:22230"]], # ["COUNT", 13], ["MIN", 12346], ["MAX", 22230], # ["MODSEQ", 917162488]]> result.to_a # => [12346, 12347, 12348, 12349, 22222, 22223, 22224, # 22225, 22226, 22227, 22228, 22229, 22230] result.uid? # => true result.count # => 13 result.min # => 12346 result.max # => 22230 result.modseq # => 917162488
使用 return
选项将结果限制为仅 min、max 和 count
result = imap.uid_search(["UID", 12345..,], return: %w(count min max)) # => #<data Net::IMAP::ESearchResult tag="RUBY0124", uid=true, # data=[["COUNT", 13], ["MIN", 12346], ["MAX", 22230]]> result.to_a # => [] result.count # => 13 result.min # => 12346 result.max # => 22230
返回选项和字符集可以作为关键字参数发送,也可以嵌入到 criteria
参数中,但它们必须按正确的顺序排列:"RETURN (...) CHARSET ... criteria..."
。以下搜索向服务器发送完全相同的命令
# Return options and charset as keyword arguments (preferred) imap.search(%w(OR UNSEEN FLAGGED), return: %w(MIN MAX), charset: "UTF-8") # Embedding return and charset in the criteria array imap.search(["RETURN", %w(MIN MAX), "CHARSET", "UTF-8", *%w(OR UNSEEN FLAGGED)]) # Embedding return and charset in the criteria string imap.search("RETURN (MIN MAX) CHARSET UTF-8 OR UNSEEN FLAGGED")
为了向后兼容,支持将字符集作为第二个位置参数发送。未来的版本可能会打印弃用警告
imap.search(%w(OR UNSEEN FLAGGED), "UTF-8", return: %w(MIN MAX))
参数转换¶ ↑
return
选项-
必须是 Array。返回选项名称可以是字符串或符号。以负整数开头和结尾的
Range
元素被编码以与PARTIAL
一起使用 - 任何其他范围都会转换为SequenceSet
。与criteria
不同,其他返回选项参数不会自动转换为SequenceSet
。 - 当
criteria
是一个 Array 时 -
当数组以
"RETURN"
开头(不区分大小写)时,第二个数组元素会像return
参数一样进行转换(如上所述)。每个其他成员都是一个
SEARCH
命令参数SequenceSet
-
使用
SequenceSet#valid_string
编码为 IMAPsequence-set
。 - Set、Range、
-1
、:*
,响应#to_sequence_set
-
转换为
SequenceSet
以进行验证和编码。 - 嵌套序列集
Array
-
当嵌套数组中的每个元素都是上述类型之一、一个正
Integer
、一个序列集格式的String
或这些相同类型的深层嵌套Array
时,该数组将被转换为SequenceSet
以进行验证和编码。 - 任何其他嵌套
Array
-
否则,嵌套数组将编码为带括号的列表,以组合多个搜索键(例如,与
OR
和NOT
一起使用)。 String
-
当它是有效的 IMAP
atom
时按原样发送,否则编码为 IMAPquoted
或literal
字符串。每个标准搜索键名称都是有效的 IMAPatom
,并且每个标准搜索键字符串参数都是一个astring
,可以编码为atom
、quoted
或literal
。注意:
*
不是有效的 IMAPatom
字符。任何包含*
的字符串都将被编码为quoted
字符串,而不是sequence-set
。 Integer
(-1
除外)-
使用
#to_s
编码。 Date
-
编码为 IMAP 日期(请参见
::encode_date
)。
- 当
criteria
是一个 String 时 -
criteria
将直接发送到服务器,不进行任何验证或编码。警告:当使用外部输入时,这很容易受到注入攻击。
支持的返回选项¶ ↑
有关标准返回选项和返回数据的完整定义,请参见相关 RFC。
ALL
-
返回
ESearchResult#all
,其中包含所有匹配的序列号或 UID 的SequenceSet
。当返回选项为空时,这是默认值。为了与
SearchResult
兼容,ESearchResult#to_a
返回消息序列号或 UID 的 Array。 COUNT
-
返回
ESearchResult#count
,其中包含匹配的消息数。 MAX
-
返回
ESearchResult#max
,其中包含最高的匹配序列号或 UID。 MIN
-
返回
ESearchResult#min
,其中包含最低的匹配序列号或 UID。 PARTIAL
range-
返回
ESearchResult#partial
,其中包含由 range 选择的匹配序列号或 UID 的子集的SequenceSet
。与序列号一样,第一个结果为1
:1..500
选择前 500 个搜索结果(按邮箱顺序),501..1000
选择第二个 500,依此类推。range 也可以是负数:-500..-1
选择最后 500 个搜索结果。
MODSEQ
返回数据¶ ↑
ESearchResult#modseq
返回数据没有对应的返回选项。相反,如果使用 MODSEQ
搜索键,或者当为选定的邮箱启用 CONDSTORE
扩展时,将返回该数据。请参见 [RFC4731 §3.2] 或 [RFC7162 §2.1.5]。
RFC4466
兼容的扩展¶ ↑
RFC4466 §2.6 定义了搜索扩展的标准语法。Net::IMAP
允许发送不支持的搜索返回选项,并将不支持的搜索扩展的返回值解析为 ExtensionData
。请注意,这是一个有意为之的不稳定 API。未来的版本可能会返回不同的(不兼容的)对象,没有弃用或警告。
搜索键¶ ↑
有关标准搜索 criteria
的完整定义,请参见 [IMAP4rev1 §6.4.4] 或 [IMAP4rev2 §6.4.4],以及任何可能定义其他搜索筛选器的 capabilities
的文档,例如 CONDSTORE
、WITHIN
、FILTERS
、SEARCH=FUZZY
、OBJECTID
或 SAVEDATE
。
除序列集和带括号的列表外,所有搜索键都由前缀标签和零个或多个参数组成。参数的数量和类型特定于每个搜索键。
匹配所有消息的搜索键¶ ↑
ALL
-
默认的初始键。匹配邮箱中的每条消息。
SAVEDATESUPPORTED
-
当邮箱支持保存日期属性时,匹配邮箱中的每条消息。否则,它不匹配任何消息。
需要
SAVEDATE
功能。 [RFC8514]
序列集搜索键¶ ↑
- 序列集
-
匹配具有 序列集 中消息序列号的消息。
注意:此搜索键没有标签。
必须不启用
UIDONLY
。 [RFC9586] UID
序列集-
匹配 UID 在 序列集 中的消息。
复合搜索键¶ ↑
- (搜索键 搜索键…)
-
将一个或多个搜索关键字参数组合起来,以匹配所有包含的搜索关键字的消息。对于带有搜索关键字参数的
OR
、NOT
和其他搜索关键字非常有用。注意:此搜索键没有标签。
OR
搜索关键字 搜索关键字-
匹配符合任一搜索关键字参数的消息。
NOT
搜索关键字-
匹配不符合搜索关键字的消息。
FUZZY
搜索关键字-
对指定的搜索关键字使用模糊匹配。
需要
SEARCH=FUZZY
功能。 [RFC6203]。
标记搜索关键字¶ ↑
ANSWERED
,UNANSWERED
-
匹配带有或不带有
\Answered
标记的消息。 DELETED
,UNDELETED
-
匹配带有或不带有
\Deleted
标记的消息。 DRAFT
,UNDRAFT
-
匹配带有或不带有
\Draft
标记的消息。 FLAGGED
,UNFLAGGED
-
匹配带有或不带有
\Flagged
标记的消息。 SEEN
,UNSEEN
-
匹配带有或不带有
\Seen
标记的消息。 KEYWORD
关键字,UNKEYWORD
关键字-
匹配带有或不带有指定关键字的消息。
RECENT
,UNRECENT
-
匹配带有或不带有
\Recent
标记的消息。注意:
\Recent
标记已从IMAP4rev2
中删除。 NEW
-
等效于
(RECENT UNSEEN)
。注意:
\Recent
标记已从IMAP4rev2
中删除。
标头字段子字符串搜索关键字¶ ↑
BCC
子字符串-
当信封的
BCC
字段中存在 子字符串 时匹配。 CC
子字符串-
当信封的
CC
字段中存在 子字符串 时匹配。 FROM
子字符串-
当信封的
FROM
字段中存在 子字符串 时匹配。 SUBJECT
子字符串-
当信封的
SUBJECT
字段中存在 子字符串 时匹配。 TO
子字符串-
当信封的
TO
字段中存在 子字符串 时匹配。 HEADER
字段 子字符串-
当指定的标头字段中存在 子字符串 时匹配。
正文文本搜索关键字¶ ↑
BODY
字符串-
当消息正文中存在 字符串 时匹配。不匹配标头字段。
服务器可能使用灵活匹配,而不是简单的子字符串匹配。例如,这可能使用词干提取或仅匹配完整单词。
TEXT
字符串-
当消息的标头或正文中存在 字符串 时匹配。
服务器可能使用灵活匹配,而不是简单的子字符串匹配。例如,这可能使用词干提取或仅匹配完整单词。
日期/时间搜索关键字¶ ↑
SENTBEFORE
日期SENTON
日期SENTSINCE
日期-
当
Date
标头早于、等于或晚于 日期 时匹配。 BEFORE
日期ON
日期SINCE
日期-
当
INTERNALDATE
早于、等于或晚于 日期 时匹配。 OLDER
间隔YOUNGER
间隔-
当
INTERNALDATE
早于/晚于 间隔 秒前时匹配。需要
WITHIN
功能。 [RFC5032] SAVEDBEFORE
日期SAVEDON
日期SAVEDSINCE
日期-
当保存日期早于、等于或晚于 日期 时匹配。
需要
SAVEDATE
功能。 [RFC8514]
其他消息属性搜索关键字¶ ↑
SMALLER
字节LARGER
字节-
当
RFC822.SIZE
小于或大于 字节 时匹配。 ANNOTATION
条目 属性 值-
匹配具有注释的消息,这些注释具有与 条目 匹配的条目、与 属性 匹配的属性以及属性值中的 值。
需要
ANNOTATE-EXPERIMENT-1
功能。 [RFC5257]。 FILTER
过滤器-
引用存储在服务器上的过滤器,并匹配所有将与该过滤器的搜索条件匹配的消息。
需要
FILTERS
功能。 [RFC5466] MODSEQ
modseq-
当
MODSEQ
大于或等于 modseq 时匹配。需要
CONDSTORE
功能。 [RFC7162]。 MODSEQ
条目 条目类型 modseq-
当特定的元数据条目自 modseq 以来已更新时匹配。
对于标记,相应的条目名称为
"/flags/#{flag_name}"
,其中 flag_name 包括\
前缀。 条目类型 可以是"shared"
、"priv"
(私有)或"all"
之一。需要
CONDSTORE
功能。 [RFC7162]。 EMAILID
对象IDTHREADID
对象ID-
当
EMAILID
/THREADID
等于 对象ID 时匹配(不支持子字符串匹配)。需要
OBJECTID
功能。 [RFC8474]
功能¶ ↑
只有当服务器支持 IMAP4rev2
或允许它们的扩展(例如 ESEARCH
[RFC4731])时,才应指定返回选项。
当启用 IMAP4rev2
时,或者当服务器支持 IMAP4rev2
但不支持 IMAP4rev1
时,始终返回 ESearchResult
而不是 SearchResult
。
如果支持 CONDSTORE 并且为所选邮箱启用,则非空的 SearchResult
将包含一个 MODSEQ
值。
imap.select("mbox", condstore: true) result = imap.search(["SUBJECT", "hi there", "not", "new"]) #=> Net::IMAP::SearchResult[1, 6, 7, 8, modseq: 5594] result.modseq # => 5594
# File net-imap-0.5.4/lib/net/imap.rb, line 2369 def search(...) search_internal("SEARCH", ...) end
发送 SELECT 命令 [IMAP4rev1 §6.3.1],以选择 mailbox
,以便可以访问 mailbox
中的消息。
选择邮箱后,您可以从 imap.responses("EXISTS", &:last)
中检索该邮箱中的项目数,并从 imap.responses("RECENT", &:last)
中检索最近的消息数。请注意,如果会话期间有新消息到达或现有消息被删除,这些值可能会更改;请参阅 add_response_handler
以了解如何检测这些事件。
当 condstore
关键字参数为 true 时,会告知服务器启用该扩展。如果 mailbox
支持 mod-sequences 的持久性,则 HIGHESTMODSEQ
ResponseCode
将作为未标记的响应发送到 select
,并且所有 'FETCH` 响应都将包含 FetchData#modseq
。否则,将发送 NOMODSEQ
ResponseCode
。
如果邮箱不存在或由于某种原因不可选,则会引发 Net::IMAP::NoResponseError
。
相关:examine
功能¶ ↑
如果支持 [UIDPLUS],服务器可能会返回带有 “UIDNOTSTICKY” 响应代码的未标记的“NO”响应,表明邮件存储不支持持久 UID
imap.responses("NO", &:last)&.code&.name == "UIDNOTSTICKY"
如果支持 [CONDSTORE],则可以使用 condstore
关键字参数。
imap.select("mbox", condstore: true) modseq = imap.responses("HIGHESTMODSEQ", &:last)
# File net-imap-0.5.4/lib/net/imap.rb, line 1422 def select(mailbox, condstore: false) args = ["SELECT", mailbox] args << ["CONDSTORE"] if condstore synchronize do @responses.clear send_command(*args) end end
发送 SETACL 命令 [RFC4314 §3.1],其中包含 mailbox
、user
和用户在该邮箱上拥有的 rights
。如果 rights
为 nil,则该用户将被剥夺对该邮箱的任何权利。
相关:getacl
功能¶ ↑
服务器的功能必须包含 ACL
[RFC4314]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1718 def setacl(mailbox, user, rights) if rights.nil? send_command("SETACL", mailbox, user, "") else send_command("SETACL", mailbox, user, rights) end end
发送 SETQUOTA 命令 [RFC2087 §4.1],其中包含指定的 mailbox
和 quota
。如果 quota
为 nil,则该邮箱的 quota
将被取消设置。通常,需要以服务器管理员身份登录才能使其工作。
功能¶ ↑
服务器的功能必须包含 QUOTA
[RFC2087]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1698 def setquota(mailbox, quota) if quota.nil? data = '()' else data = '(STORAGE ' + quota.to_s + ')' end send_command("SETQUOTA", mailbox, RawData.new(data)) end
发送 SORT 命令 [RFC5256 §3],以搜索与 search_keys
匹配的邮箱消息,并返回按 sort_keys
排序的消息序列号数组。 search_keys
的解释方式与 search
相同。
相关:uid_sort
、search
、uid_search
、thread
、uid_thread
例如:¶ ↑
p imap.sort(["FROM"], ["ALL"], "US-ASCII") #=> [1, 2, 3, 5, 6, 7, 8, 4, 9] p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII") #=> [6, 7, 8, 1]
功能¶ ↑
服务器的功能必须包含 SORT
[RFC5256]。
# File net-imap-0.5.4/lib/net/imap.rb, line 2658 def sort(sort_keys, search_keys, charset) return sort_internal("SORT", sort_keys, search_keys, charset) end
发送 STARTTLS 命令 [IMAP4rev1 §6.2.1] 以启动 TLS 会话。
任何 options
都将直接转发到 OpenSSL::SSL::SSLContext#set_params;键是 SSLContext 上属性分配方法的名称。
有关已弃用的参数,请参阅 DeprecatedClientOptions#starttls
。
此方法在 TLS 协商和主机名验证都成功后返回。任何错误都表示连接未被安全保护。
注意
在 STARTTLS 之前添加的任何
response_handlers
都应该意识到,发送给 STARTTLS 的TaggedResponse
是以明文形式发送的,在 TLS 协商之前。TLS 在该响应之后立即开始。随响应发送的任何响应代码(例如 CAPABILITY)都是不安全的,不能信任。
相关:Net::IMAP.new
,login
,authenticate
功能¶ ↑
除非服务器声明了 STARTTLS
功能,否则客户端不应调用 starttls
。
服务器功能在 starttls
、login
和 authenticate
之后可能会发生变化。当此方法完成时,缓存的 capabilities
将被清除。
# File net-imap-0.5.4/lib/net/imap.rb, line 1229 def starttls(**options) @ssl_ctx_params, @ssl_ctx = build_ssl_ctx(options) send_command("STARTTLS") do |resp| if resp.kind_of?(TaggedResponse) && resp.name == "OK" clear_cached_capabilities clear_responses start_tls_session end end end
发送 STATUS 命令 [IMAP4rev1 §6.3.10] 并返回指示的 mailbox
的状态。attr
是一个或多个要请求状态的属性列表。
返回值是一个属性哈希。大多数状态属性返回整数值,但有些返回其他值类型(如下所述)。
如果无法返回 mailbox
的状态值,则会引发 Net::IMAP::NoResponseError
;例如,因为它不存在。
支持的属性¶ ↑
MESSAGES
-
邮箱中的消息数。
UIDNEXT
-
邮箱的下一个唯一标识符值。
UIDVALIDITY
-
邮箱的唯一标识符有效性值。
UNSEEN
-
不带
\Seen
标志的消息数。 DELETED
-
带有
\Deleted
标志的消息数。 SIZE
-
邮箱的大概大小—必须大于或等于所有消息的
RFC822.SIZE
获取项值的总和。 HIGHESTMODSEQ
-
邮箱中所有消息的最高修改序列值。请参阅
CONDSTORE
[RFC7162]。 MAILBOXID
-
服务器分配的邮箱唯一字符串标识符。请参阅
OBJECTID
[RFC8474]。 RECENT
-
带有
\Recent
标志的消息数。注意:RECENT
已从 IMAP4rev2 中删除。
可以请求不支持的属性。属性值将为整数或 ExtensionData
对象。
例如:¶ ↑
p imap.status("inbox", ["MESSAGES", "RECENT"]) #=> {"RECENT"=>0, "MESSAGES"=>44}
功能¶ ↑
SIZE
要求服务器的功能包括 IMAP4rev2
或 STATUS=SIZE
[RFC8483]。
DELETED
要求服务器的功能包括 IMAP4rev2
。
HIGHESTMODSEQ
要求服务器的功能包括 CONDSTORE
[RFC7162]。
MAILBOXID
要求服务器的功能包括 OBJECTID
[RFC8474]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1818 def status(mailbox, attr) synchronize do send_command("STATUS", mailbox, attr) clear_responses("STATUS").last&.attr end end
发送 STORE 命令 [IMAP4rev1 §6.4.6] 以更改邮箱中与消息关联的数据,特别是它们的标志。
set
是一个数字、一个数字数组或一个 Range 对象。每个数字都是一个消息序列号。
attr
是要存储的数据项的名称。value
的语义根据 attr
而变化。
-
当
attr
为"FLAGS"
时,value
中的标志将替换消息的标志列表。 -
当
attr
为"+FLAGS"
时,value
中的标志将添加到消息的标志中。 -
当
attr
为"-FLAGS"
时,value
中的标志将从消息中删除。
unchangedsince
是一个可选的整数修改序列。它禁止对 mod-sequence
大于指定的 unchangedsince
值的消息进行任何更改。如果任何消息未能通过此检查,则会在 MODIFIED
ResponseCode
中返回 SequenceSet
。
返回值是 FetchData
的数组。
相关:uid_store
例如:¶ ↑
p imap.store(6..8, "+FLAGS", [:Deleted]) #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
功能¶ ↑
扩展可以定义新的数据项以与 store
一起使用。
服务器的功能必须包括 CONDSTORE
[RFC7162] 才能使用 unchangedsince
参数。使用 unchangedsince
会隐式启用 CONDSTORE
扩展。
# File net-imap-0.5.4/lib/net/imap.rb, line 2542 def store(set, attr, flags, unchangedsince: nil) store_internal("STORE", set, attr, flags, unchangedsince: unchangedsince) end
发送 SUBSCRIBE 命令 [IMAP4rev1 §6.3.6],将指定的 mailbox
名称添加到服务器的“活动”或“已订阅”邮箱集中,如 lsub
返回的那样。
如果无法订阅 mailbox
,则会引发 Net::IMAP::NoResponseError
;例如,因为它不存在。
相关:unsubscribe
,lsub
,list
# File net-imap-0.5.4/lib/net/imap.rb, line 1493 def subscribe(mailbox) send_command("SUBSCRIBE", mailbox) end
发送 THREAD 命令 [RFC5256 §3] 来搜索邮箱并以线程格式返回消息序列号,作为 ThreadMember
树。search_keys
的解释与 search
的解释相同。
支持的算法包括
- ORDEREDSUBJECT
-
根据主题拆分为单级线程,按日期排序。
- REFERENCES
-
通过父/子关系拆分为线程,该关系由哪个消息是哪个消息的回复来确定。
与 search
不同,charset
是必需的参数。US-ASCII 和 UTF-8 是示例值。
相关:uid_thread
,search
,uid_search
,sort
,uid_sort
功能¶ ↑
服务器的功能必须包括 THREAD
[RFC5256]。
# File net-imap-0.5.4/lib/net/imap.rb, line 2698 def thread(algorithm, search_keys, charset) return thread_internal("THREAD", algorithm, search_keys, charset) end
在 TLS 协商完成并已验证远程主机名后返回 true。当已建立 TLS 但禁用对等验证时返回 false。
# File net-imap-0.5.4/lib/net/imap.rb, line 968 def tls_verified?; @tls_verified end
发送 UID EXPUNGE 命令 [RFC4315 §2.1] [IMAP4rev2 §6.4.9] 以永久删除所有同时设置了 \Deleted
标志且 UID 包含在 uid_set
中的消息。
返回与 expunge
相同的结果类型。
通过在与服务器重新同步时使用 uid_expunge
而不是 expunge
,客户端可以确保它不会无意中删除在客户端上次连接和客户端重新同步之间由其他客户端标记为 \Deleted
的任何消息。
相关:expunge
功能¶ ↑
服务器的功能必须包括 IMAP4rev2
或 UIDPLUS
[RFC4315]。
否则,uid_expunge
将以与 expunge
相同的方式通过扩展进行更新。
# File net-imap-0.5.4/lib/net/imap.rb, line 1958 def uid_expunge(uid_set) expunge_internal("UID EXPUNGE", SequenceSet.new(uid_set)) end
发送 UID FETCH 命令 [IMAP4rev1 §6.4.8] 以检索邮箱中与消息关联的数据。
set
是要获取的消息 UID,并且可以是 SequenceSet[…] 的任何有效输入。(对于消息序列号,请改用 fetch
。)
attr
的行为与 fetch
相同。
注意: 服务器必须隐式地将
UID
消息数据项作为任何由UID
命令引起的FETCH
响应的一部分,无论是否将UID
指定为FETCH
的消息数据项。
changedsince
(可选)的行为与 fetch
相同。
partial
是一个可选的范围,用于限制返回结果的数量。当 set
包含未知数量的消息时,它非常有用。1..500
返回 set
中的前 500 条消息(按邮箱顺序),501..1000
返回第二个 500 条消息,依此类推。partial
也可以是负数:-500..-1
选择 set
中的最后 500 条消息。需要 PARTIAL
功能。 [RFC9394]
例如
# Without partial, the size of the results may be unknown beforehand: results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS)) # ... maybe wait for a long time ... and allocate a lot of memory ... results.size # => 0..2**32-1 process results # may also take a long time and use a lot of memory... # Using partial, the results may be paginated: loop do results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS), partial: 1..500) # fetch should return quickly and allocate little memory results.size # => 0..500 break if results.empty? next_uid_to_fetch = results.last.uid + 1 process results end
功能¶ ↑
服务器的功能必须包括 PARTIAL
[RFC9394] 才能使用 partial
参数。
否则,与 fetch
相同。
# File net-imap-0.5.4/lib/net/imap.rb, line 2495 def uid_fetch(...) fetch_internal("UID FETCH", ...) end
发送一个 UID MOVE 命令 [RFC6851 §3.2] [IMAP4rev2 §6.4.9],将指定的消息移动到指定的目标 mailbox
的末尾。
与 move
类似,但 set
包含唯一标识符。
相关:move
功能¶ ↑
与 move
相同:服务器的功能必须包括 MOVE
[RFC6851]。UIDPLUS
也会以影响 move
的相同方式影响 uid_move
。
# File net-imap-0.5.4/lib/net/imap.rb, line 2632 def uid_move(set, mailbox) copy_internal("UID MOVE", set, mailbox) end
发送一个 UID SEARCH 命令 [IMAP4rev1 §6.4.8],在邮箱中搜索符合给定搜索条件的消息,并返回唯一标识符(UID
)。
返回一个 SearchResult
对象。SearchResult
继承自 Array(为了向后兼容),但在启用 CONDSTORE
功能时添加 SearchResult#modseq
。
有关参数的文档,请参阅 search
。
# File net-imap-0.5.4/lib/net/imap.rb, line 2386 def uid_search(...) search_internal("UID SEARCH", ...) end
发送一个 UID SORT 命令 [RFC5256 §3],在邮箱中搜索匹配 search_keys
的消息,并返回一个按 sort_keys
排序的唯一标识符数组。search_keys
的解释方式与 search
相同。
相关:sort
, search
, uid_search
, thread
, uid_thread
功能¶ ↑
服务器的功能必须包含 SORT
[RFC5256]。
# File net-imap-0.5.4/lib/net/imap.rb, line 2673 def uid_sort(sort_keys, search_keys, charset) return sort_internal("UID SORT", sort_keys, search_keys, charset) end
发送一个 UID STORE 命令 [IMAP4rev1 §6.4.8],以更改与邮箱中消息关联的数据,特别是它们的标志。
与 store
类似,但 set
包含唯一标识符而不是消息序列号。
相关:store
功能¶ ↑
与 store
相同。
# File net-imap-0.5.4/lib/net/imap.rb, line 2560 def uid_store(set, attr, flags, unchangedsince: nil) store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince) end
发送一个 UID THREAD 命令 [RFC5256 §3],类似于 thread
,但返回唯一标识符而不是消息序列号。
相关:thread
, search
, uid_search
, sort
, uid_sort
功能¶ ↑
服务器的功能必须包括 THREAD
[RFC5256]。
# File net-imap-0.5.4/lib/net/imap.rb, line 2712 def uid_thread(algorithm, search_keys, charset) return thread_internal("UID THREAD", algorithm, search_keys, charset) end
发送一个 UNSELECT 命令 [RFC3691 §2] [IMAP4rev2 §6.4.2],以释放邮箱的会话资源并返回到“已认证”状态。这与 close
相同,只是 \Deleted
消息不会从邮箱中删除。
相关:close
功能¶ ↑
服务器的功能必须包括 UNSELECT
[RFC3691]。
# File net-imap-0.5.4/lib/net/imap.rb, line 1898 def unselect send_command("UNSELECT") end
发送一个 UNSUBSCRIBE 命令 [IMAP4rev1 §6.3.7],以从服务器的“活动”或“订阅”邮箱集合中删除指定的 mailbox
名称。
如果无法取消订阅 mailbox
,例如,因为客户端当前未订阅它,则会引发 Net::IMAP::NoResponseError
。
# File net-imap-0.5.4/lib/net/imap.rb, line 1506 def unsubscribe(mailbox) send_command("UNSUBSCRIBE", mailbox) end
发送一个 XLIST 命令,并从客户端可用的所有名称的完整集合中返回一个名称子集。refname
提供一个上下文(例如,基于目录的邮箱层次结构中的基本目录)。mailbox
指定该上下文下的一个或多个邮箱(通过通配符)。可以在 mailbox
中使用两个通配符:“*”,它匹配所有字符,包括层次结构分隔符(例如,在基于 UNIX 的目录托管的邮箱层次结构上使用“/”);和“%”,它匹配所有字符,除了层次结构分隔符。
如果 refname
为空,则直接使用 mailbox
来确定要匹配哪些邮箱。如果 mailbox
为空,则返回 refname
的根名称和层次结构分隔符。
XLIST 命令类似于 LIST 命令,只是返回的标志引用文件夹/邮箱的功能,例如 :Sent
返回值是 MailboxList
对象的数组。例如
imap.create("foo/bar") imap.create("foo/baz") p imap.xlist("", "foo/%") #=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, \\ #<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, \\ #<Net::IMAP::MailboxList attr=[:Noinferiors], delim="/", name="foo/baz">]
相关:list
, MailboxList
功能¶ ↑
服务器的功能必须包括 XLIST
,这是一个已弃用的 Gmail 扩展(已被 SPECIAL-USE
取代)。
# File net-imap-0.5.4/lib/net/imap.rb, line 1641 def xlist(refname, mailbox) synchronize do send_command("XLIST", refname, mailbox) clear_responses("XLIST") end end
私有实例方法
# File net-imap-0.5.4/lib/net/imap.rb, line 3533 def build_ssl_ctx(ssl) if ssl params = (Hash.try_convert(ssl) || {}).freeze context = SSLContext.new context.set_params(params) if defined?(VerifyCallbackProc) context.verify_callback = VerifyCallbackProc end context.freeze [params, context] else false end end
注意:仅对问候语、登录和身份验证调用此方法
# File net-imap-0.5.4/lib/net/imap.rb, line 3270 def capabilities_from_resp_code(resp) return unless %w[PREAUTH OK].any? { _1.casecmp? resp.name } return unless (code = resp.data.code) return unless code.name.casecmp?("CAPABILITY") code.data.freeze end
# File net-imap-0.5.4/lib/net/imap.rb, line 3515 def coerce_search_arg_to_seqset?(obj) case obj when Set, -1, :* then true when Range then true when Array then obj.all? { coerce_search_array_arg_to_seqset? _1 } else obj.respond_to?(:to_sequence_set) end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3524 def coerce_search_array_arg_to_seqset?(obj) case obj when Integer then obj.positive? || obj == -1 when String then ResponseParser::Patterns::SEQUENCE_SET_STR.match?(obj.b) else coerce_search_arg_to_seqset?(obj) end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3401 def convert_return_opts(unconverted) return_opts = Array.try_convert(unconverted) or raise TypeError, "expected return options to be Array, got %s" % [ unconverted.class ] return_opts.map {|opt| case opt when Symbol then opt.to_s when PartialRange::Negative then PartialRange[opt] when Range then SequenceSet[opt] else opt end } end
# File net-imap-0.5.4/lib/net/imap.rb, line 3484 def copy_internal(cmd, set, mailbox) send_command(cmd, SequenceSet.new(set), mailbox) end
# File net-imap-0.5.4/lib/net/imap.rb, line 3339 def enforce_logindisabled? if config.enforce_logindisabled == :when_capabilities_cached capabilities_cached? else config.enforce_logindisabled end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3347 def expunge_internal(...) synchronize do send_command(...) expunged_array = clear_responses("EXPUNGE") vanished_array = extract_responses("VANISHED") { !_1.earlier? } if vanished_array.empty? expunged_array elsif vanished_array.length == 1 vanished_array.first else merged_uids = SequenceSet[*vanished_array.map(&:uids)] VanishedData[uids: merged_uids, earlier: false] end end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3442 def fetch_internal(cmd, set, attr, mod = nil, partial: nil, changedsince: nil) set = SequenceSet[set] if partial mod ||= [] mod << "PARTIAL" << PartialRange[partial] end if changedsince mod ||= [] mod << "CHANGEDSINCE" << Integer(changedsince) end case attr when String then attr = RawData.new(attr) when Array then attr = attr.map { |arg| arg.is_a?(String) ? RawData.new(arg) : arg } end synchronize do clear_responses("FETCH") if mod send_command(cmd, set, attr, mod) else send_command(cmd, set, attr) end clear_responses("FETCH") end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3319 def generate_tag @tagno += 1 return format("%s%04d", @tag_prefix, @tagno) end
# File net-imap-0.5.4/lib/net/imap.rb, line 3233 def get_response buff = String.new while true s = @sock.gets(CRLF) break unless s buff.concat(s) if /\{(\d+)\}\r\n/n =~ s s = @sock.read($1.to_i) buff.concat(s) else break end end return nil if buff.length == 0 if config.debug? $stderr.print(buff.gsub(/^/n, "S: ")) end return @parser.parse(buff) end
# File net-imap-0.5.4/lib/net/imap.rb, line 3112 def get_server_greeting greeting = get_response raise Error, "No server greeting - connection closed" unless greeting record_untagged_response_code greeting raise ByeResponseError, greeting if greeting.name == "BYE" greeting end
# File net-imap-0.5.4/lib/net/imap.rb, line 3205 def get_tagged_response(tag, cmd, timeout = nil) if timeout deadline = Time.now + timeout end until @tagged_responses.key?(tag) raise @exception if @exception if timeout timeout = deadline - Time.now if timeout <= 0 return nil end end @tagged_response_arrival.wait(timeout) end resp = @tagged_responses.delete(tag) case resp.name when /\A(?:OK)\z/ni return resp when /\A(?:NO)\z/ni raise NoResponseError, resp when /\A(?:BAD)\z/ni raise BadResponseError, resp else disconnect raise InvalidResponseError, "invalid tagged resp: %p" % [resp.raw.chomp] end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3504 def normalize_searching_criteria(criteria) return [RawData.new(criteria)] if criteria.is_a?(String) criteria.map {|i| if coerce_search_arg_to_seqset?(i) SequenceSet[i] else i end } end
# File net-imap-0.5.4/lib/net/imap.rb, line 3324 def put_string(str) @sock.print(str) if config.debug? if @debug_output_bol $stderr.print("C: ") end $stderr.print(str.gsub(/\n/n) { $'.empty? ? $& : "\nC: " }) if /\n\z/n.match(str) @debug_output_bol = true else @debug_output_bol = false end end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3138 def receive_responses connection_closed = false until connection_closed synchronize do @exception = nil end begin resp = get_response rescue Exception => e synchronize do @sock.close @exception = e end break end unless resp synchronize do @exception = EOFError.new("end of file reached") end break end begin synchronize do case resp when TaggedResponse @tagged_responses[resp.tag] = resp @tagged_response_arrival.broadcast case resp.tag when @logout_command_tag return when @continued_command_tag @continuation_request_exception = RESPONSE_ERRORS[resp.name].new(resp) @continuation_request_arrival.signal end when UntaggedResponse record_untagged_response(resp) if resp.name == "BYE" && @logout_command_tag.nil? @sock.close @exception = ByeResponseError.new(resp) connection_closed = true end when ContinuationRequest @continuation_request_arrival.signal end @response_handlers.each do |handler| handler.call(resp) end end rescue Exception => e @exception = e synchronize do @tagged_response_arrival.broadcast @continuation_request_arrival.broadcast end end end synchronize do @receiver_thread_terminating = true @tagged_response_arrival.broadcast @continuation_request_arrival.broadcast if @idle_done_cond @idle_done_cond.signal end end end
存储 name => […, data]
# File net-imap-0.5.4/lib/net/imap.rb, line 3257 def record_untagged_response(resp) @responses[resp.name] << resp.data record_untagged_response_code resp end
存储 code.name => […, code.data]
# File net-imap-0.5.4/lib/net/imap.rb, line 3263 def record_untagged_response_code(resp) return unless resp.data.is_a?(ResponseText) return unless (code = resp.data.code) @responses[code.name] << code.data end
# File net-imap-0.5.4/lib/net/imap.rb, line 3562 def sasl_adapter SASLAdapter.new(self, &method(:send_command_with_continuations)) end
# File net-imap-0.5.4/lib/net/imap.rb, line 3367 def search_args(keys, charset_arg = nil, return: nil, charset: nil) {return:} => {return: return_kw} case [return_kw, keys] in [nil, Array[RETURN_WHOLE, return_opts, *keys]] return_opts = convert_return_opts(return_opts) esearch = true in [nil => return_opts, RETURN_START] esearch = true in [nil => return_opts, keys] esearch = false in [_, Array[RETURN_WHOLE, _, *] | RETURN_START] raise ArgumentError, "conflicting return options" in [_, Array[RETURN_WHOLE, _, *]] # workaround for https://bugs.ruby-lang.org/issues/20956 raise ArgumentError, "conflicting return options" in [_, RETURN_START] # workaround for https://bugs.ruby-lang.org/issues/20956 raise ArgumentError, "conflicting return options" in [return_opts, keys] return_opts = convert_return_opts(return_opts) esearch = true end if charset && charset_arg raise ArgumentError, "multiple charset arguments" end charset ||= charset_arg # NOTE: not handling combined RETURN and CHARSET for raw strings if charset && keys in /\ACHARSET\b/i | Array[/\ACHARSET\z/i, *] raise ArgumentError, "multiple charset arguments" end args = normalize_searching_criteria(keys) args.prepend("CHARSET", charset) if charset args.prepend("RETURN", return_opts) if return_opts return args, esearch end
# File net-imap-0.5.4/lib/net/imap.rb, line 3416 def search_internal(cmd, ...) args, esearch = search_args(...) synchronize do tagged = send_command(cmd, *args) tag = tagged.tag # Only the last ESEARCH or SEARCH is used. Excess results are ignored. esearch_result = extract_responses("ESEARCH") {|response| response in ESearchResult(tag: ^tag) }.last search_result = clear_responses("SEARCH").last if esearch_result # silently ignore SEARCH results, if any esearch_result elsif search_result # warn EXPECTED_ESEARCH_RESULT if esearch search_result elsif esearch # warn NO_SEARCH_RESPONSE ESearchResult[tag:, uid: cmd.start_with?("UID ")] else # warn NO_SEARCH_RESPONSE SearchResult[] end end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3291 def send_command(cmd, *args, &block) synchronize do args.each do |i| validate_data(i) end tag = generate_tag put_string(tag + " " + cmd) args.each do |i| put_string(" ") send_data(i, tag) end put_string(CRLF) if cmd == "LOGOUT" @logout_command_tag = tag end if block add_response_handler(&block) end begin return get_tagged_response(tag, cmd) ensure if block remove_response_handler(block) end end end end
调用 send_command
,产生每个 ContinuationRequest
的文本,并使用每个块结果进行响应。返回 TaggedResponse
。引发 NoResponseError
或 BadResponseError
。
# File net-imap-0.5.4/lib/net/imap.rb, line 3282 def send_command_with_continuations(cmd, *args) send_command(cmd, *args) do |server_response| if server_response.instance_of?(ContinuationRequest) client_response = yield server_response.data.text put_string(client_response + CRLF) end end end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 34 def send_data(data, tag = nil) case data when nil put_string("NIL") when String send_string_data(data, tag) when Integer send_number_data(data) when Array send_list_data(data, tag) when Time, DateTime send_time_data(data) when Date send_date_data(data) when Symbol send_symbol_data(data) else data.send_data(self, tag) end end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 116 def send_date_data(date) put_string Net::IMAP.encode_date(date) end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 102 def send_list_data(list, tag = nil) put_string("(") first = true list.each do |i| if first first = false else put_string(" ") end send_data(i, tag) end put_string(")") end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 81 def send_literal(str, tag = nil) synchronize do put_string("{" + str.bytesize.to_s + "}" + CRLF) @continued_command_tag = tag @continuation_request_exception = nil begin @continuation_request_arrival.wait e = @continuation_request_exception || @exception raise e if e put_string(str) ensure @continued_command_tag = nil @continuation_request_exception = nil end end end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 98 def send_number_data(num) put_string(num.to_s) end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 77 def send_quoted_string(str) put_string('"' + str.gsub(/["\\]/, "\\\\\\&") + '"') end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 55 def send_string_data(str, tag = nil) if str.empty? put_string('""') elsif str.match?(/[\r\n]/n) # literal, because multiline send_literal(str, tag) elsif !str.ascii_only? if @utf8_strings # quoted string send_quoted_string(str) else # literal, because of non-ASCII bytes send_literal(str, tag) end elsif str.match?(/[(){ \x00-\x1f\x7f%*"\\]/n) # quoted string send_quoted_string(str) else put_string(str) end end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 119 def send_symbol_data(symbol) put_string("\\" + symbol.to_s) end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 117 def send_time_data(time) put_string Net::IMAP.encode_time(time) end
# File net-imap-0.5.4/lib/net/imap.rb, line 3488 def sort_internal(cmd, sort_keys, search_keys, charset) search_keys = normalize_searching_criteria(search_keys) synchronize do send_command(cmd, sort_keys, charset, *search_keys) clear_responses("SORT").last || [] end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3103 def start_imap_connection @greeting = get_server_greeting @capabilities = capabilities_from_resp_code @greeting @receiver_thread = start_receiver_thread rescue Exception @sock.close raise end
# File net-imap-0.5.4/lib/net/imap.rb, line 3120 def start_receiver_thread Thread.start do receive_responses rescue Exception => ex @receiver_thread_exception = ex # don't exit the thread with an exception end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3548 def start_tls_session raise "SSL extension not installed" unless defined?(OpenSSL::SSL) raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket) raise "cannot start TLS without SSLContext" unless ssl_ctx @sock = SSLSocket.new(@sock, ssl_ctx) @sock.sync_close = true @sock.hostname = @host if @sock.respond_to? :hostname= ssl_socket_connect(@sock, open_timeout) if ssl_ctx.verify_mode != VERIFY_NONE @sock.post_connection_check(@host) @tls_verified = true end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3472 def store_internal(cmd, set, attr, flags, unchangedsince: nil) attr = RawData.new(attr) if attr.instance_of?(String) args = [SequenceSet.new(set)] args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince args << attr << flags synchronize do clear_responses("FETCH") send_command(cmd, *args) clear_responses("FETCH") end end
# File net-imap-0.5.4/lib/net/imap.rb, line 3129 def tcp_socket(host, port) s = Socket.tcp(host, port, :connect_timeout => open_timeout) s.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, true) s rescue Errno::ETIMEDOUT raise Net::OpenTimeout, "Timeout to open TCP connection to " + "#{host}:#{port} (exceeds #{open_timeout} seconds)" end
# File net-imap-0.5.4/lib/net/imap.rb, line 3496 def thread_internal(cmd, algorithm, search_keys, charset) search_keys = normalize_searching_criteria(search_keys) synchronize do send_command(cmd, algorithm, charset, *search_keys) clear_responses("THREAD").last || [] end end
# File net-imap-0.5.4/lib/net/imap/command_data.rb, line 13 def validate_data(data) case data when nil when String when Integer NumValidator.ensure_number(data) when Array if data[0] == 'CHANGEDSINCE' NumValidator.ensure_mod_sequence_value(data[1]) else data.each do |i| validate_data(i) end end when Time, Date, DateTime when Symbol else data.validate end end
基本邮箱属性
↑ 返回顶部常量
- HASCHILDREN
与
HAS_CHILDREN
的别名,与 IMAP 拼写匹配。- HASNOCHILDREN
与
HAS_NO_CHILDREN
的别名,与 IMAP 拼写匹配。- HAS_CHILDREN
此属性的存在表示邮箱具有子邮箱。如果存在子邮箱且用户没有权限访问任何子邮箱,则服务器不应设置此属性。在这种情况下,应该使用
\HasNoChildren
。 然而,在许多情况下,服务器可能无法有效地计算用户是否有权访问任何子邮箱。请注意,即使邮箱的\HasChildren
属性在处理邮箱时必须正确,客户端也必须准备好处理邮箱标记为\HasChildren
属性的情况,但在对list
命令的响应中没有出现子邮箱。例如,这可能是由于子邮箱被删除或在服务器能够列出它们之前被另一个客户端(使用访问控制)设置为用户无法访问。服务器在同一个
list
响应中同时返回\HasChildren
和\HasNoChildren
属性是错误的。遇到同时存在\HasChildren
和\HasNoChildren
属性的list
响应的客户端应视为list
响应中都缺失这两个属性。- HAS_NO_CHILDREN
此属性的存在表示邮箱没有当前经过身份验证的用户可以访问的子邮箱。
服务器在同一个
list
响应中同时返回\HasChildren
和\HasNoChildren
属性是错误的。遇到同时存在\HasChildren
和\HasNoChildren
属性的list
响应的客户端应视为list
响应中都缺失这两个属性。注意:
\HasNoChildren
属性不应与\NoInferiors
属性混淆,后者表示现在不存在子邮箱,并且将来也无法创建子邮箱。- MARKED
邮箱已被服务器标记为“感兴趣”;邮箱可能包含自上次选择邮箱以来添加的消息。
如果服务器无法确定邮箱是否“有趣”,则服务器不应发送
\Marked
或\Unmarked
。对于单个邮箱,服务器不得发送超过一个\Marked
、\Unmarked
和\NoSelect
,并且可以不发送任何一个。- NOINFERIORS
与
NO_INFERIORS
的别名,与 IMAP 拼写匹配。- NONEXISTENT
\NonExistent
属性表示邮箱名称不指向现有邮箱。请注意,此属性本身没有意义,因为与规范list
模式匹配但不存在的邮箱名称,除非满足下面列出的两个条件之一,否则不得返回。-
邮箱名称也满足选择标准(例如,它已订阅并且已指定“SUBSCRIBED”选择选项)。
-
已指定“RECURSIVEMATCH”,并且邮箱名称至少有一个不匹配
list
模式且确实匹配选择标准的后代邮箱名称。
实际上,这意味着
\NonExistent
属性通常与\Subscribed
、\Remote
、\HasChildren
或 CHILDINFO 扩展数据项中的一个或多个一起返回。客户端必须将
\NonExistent
属性的存在视为服务器也发送了\NoSelect
属性-
- NOSELECT
与
NO_SELECT
的别名,与 IMAP 拼写匹配。- NO_INFERIORS
邮箱属性,表示此名称下不可能存在任何子层级;现在不存在子层级,并且将来也无法创建子层级。
客户端必须将
\NoInferiors
属性的存在视为服务器也发送了\HasNoChildren
属性- NO_SELECT
邮箱属性,表示不可能将此名称用作可选择的邮箱。
- REMOTE
邮箱是一个远程邮箱。
- SUBSCRIBED
邮箱名称是使用
subscribe
命令订阅的。- UNMARKED
自上次选择邮箱以来,该邮箱不包含任何其他消息。
如果服务器无法确定邮箱是否“有趣”,则服务器不应发送
\Marked
或\Unmarked
。对于单个邮箱,服务器不得发送超过一个\Marked
、\Unmarked
和\NoSelect
,并且可以不发送任何一个。
邮箱角色属性
↑ 返回顶部常量
- ALL
邮箱属性,表示此邮箱显示用户消息存储中的所有消息。实现可以省略某些消息,例如垃圾箱和垃圾邮件中的消息。当支持此特殊用途时,几乎可以肯定它代表一个虚拟邮箱。
- ARCHIVE
邮箱属性,表示此邮箱用于存档消息。“存档”邮箱的含义取决于服务器;通常,它将用于将消息移出收件箱,或者以其他方式使其远离用户,同时仍使其可访问。
- DRAFTS
邮箱属性,表示此邮箱用于保存草稿消息——通常是正在撰写但尚未发送的消息。在某些服务器实现中,这可能是一个虚拟邮箱,其中包含来自其他邮箱的标记为“草稿”消息标志的消息。或者,这可能只是建议客户端将草稿放在此处。
- JUNK
邮箱属性,表示此邮箱是存放被视为垃圾邮件的消息的位置。一些服务器实现可能会自动将消息放在此处。或者,这可能只是对客户端垃圾邮件过滤器的建议。
- SENT
邮箱属性,表示此邮箱用于保存已发送消息的副本。一些服务器实现可能会自动将消息放在此处。或者,这可能只是建议客户端将已发送消息保存在此处。
- TRASH
邮箱属性,表示此邮箱用于保存已删除或标记为删除的消息。在某些服务器实现中,这可能是一个虚拟邮箱,其中包含来自其他邮箱的标记为
\Deleted
消息标志的消息。或者,这可能只是建议选择不使用 IMAP\Deleted
模型的客户端应将其用作垃圾箱位置。在严格期望 IMAP\Deleted
模型的服务器实现中,可能不支持此特殊用途。
系统标志
↑ 返回顶部常量
- ANSWERED
表示消息已被回复的标志。
- DELETED
表示消息已标记为删除的标志。这将在邮箱关闭或清除时发生。
- DRAFT
表示消息只是草稿或正在进行中的版本的标志。
- FLAGGED
表示消息已被标记为特殊或紧急注意的消息标志。
也是一个邮箱特殊用途属性,表示此邮箱显示所有以某种方式标记为“重要”的消息。当支持此特殊用途时,它很可能代表一个虚拟邮箱,收集(来自其他邮箱的)标记为“已标记”消息标志的消息。
- RECENT
表示消息是“最近”的标志,这意味着此会话是客户端第一次收到此消息通知的会话。
- SEEN
表示消息已被阅读的标志。