IMAP 简介:
IMAP(Internet Mail Access Protocol)以前称作交互邮件访问协议(Interactive Mail Access Protocol),是一个应用层协议。IMAP是斯坦福大学在1986年开发的一种邮件获取协议。它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。当前的权威定义是RFC3501。IMAP协议运行在TCP/IP协议之上,使用的端口是143。它与POP3协议的主要区别是用户可以不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作。
IMAP和POP3(Post Office Protocol - Version 3,邮局协议第三版)是邮件访问最为普遍的Internet标准协议。事实上所有现代的邮件客户端和服务器都对两者给予支持。IMAP版本是“IMAP第四版第一次修订版”(IMAP4rev1),在RFC 3501中定义。
IMAP 特点
IMAP由Mark Crispin设计,对于邮件访问提供了相对于广泛使用的POP3邮件协议的另外一种选择。基本上,两者都允许一个邮件客户端访问邮件服务器上存储的信息。一些只在IMAP中存在的重要方面包括:
-
支持连接和断开两种操作模式。当使用POP3时,客户端只会在一段时间内连接到服务器,直到它下载完所有新信息,客户端即断开连接。在IMAP中,只要用户界面是活动的和下载信息内容是需要的,客户端就会一直连接服务器。对于有很多或者很大邮件的用户来说,使用IMAP4模式可以获得更快的响应时间。
-
支持多个客户同时连接到一个邮箱。POP3协议假定邮箱当前的连接是唯一的连接。相反,IMAP4协议允许多个用户同时访问邮箱同时提供一种机制让客户能够感知其他当前连接到这个邮箱的用户所做的操作。
-
支持访问消息中的MIME部分和部分获取。几乎所有的Internet邮件都是以MIME格式传输的。MIME允许消息包含一个树型结构,这个树型结构的叶子节点都是单一内容类型而非叶子节点都是多块类型的组合。IMAP4协议允许客户端获取任何独立的MIME部分和获取信息的一部分或者全部。这些机制使得用户无需下载附件就可以浏览消息内容或者在获取内容的同时浏览。
-
支持在服务器保留消息状态信息。通过使用在IMAP4协议中定义的标志客户端可以跟踪消息状态,例如邮件是否被读取,回复,或者删除。这些标识存储在服务器,所以多个客户在不同时间访问一个邮箱可以感知其他用户所做的操作。
-
支持在服务器上访问多个邮箱。IMAP4客户端可以在服务器上创建,重命名,或删除邮箱(通常以文件夹形式显现给用户)。支持多个邮箱还允许服务器提供对于共享和公共文件夹的访问。
-
支持服务器端搜索。IMAP4提供了一种机制给客户使客户可以要求服务器搜索匹配多个标准的信息。在这种机制下客户端就无需下载邮箱中所有信息来完成这些搜索。
-
支持一个定义良好的扩展机制。吸取早期Internet协议的经验,IMAP的扩展定义了一个明确的机制。很多对于原始协议的扩展已被提议并广泛使用。无论使用POP3还是IMAP4来获取消息,客户端均使用SMTP协议来发送消息。邮件客户端可能是POP客户端或者IMAP客户端,但都会使用SMTP。
大多数邮件程序的目录服务还使用LDAP。
不像大多数旧的Internet协议,IMAP4生来就支持加密注册机制。IMAP4中也支持明文传输密码。因为加密机制的使用需要客户端和服务器双方的一致,明文密码的使用是在一些客户端和服务器类型不同的情况下(例如Microsoft Windows客户端和非Windows服务器)。使用SSL也可以对IMAP4的通信进行加密,通过将在SSL上的IMAP4通信通过993端口传输或者在IMAP4线程创建的时候声明“STARTTLS”。
IMAP4使用端口143在TCP/IP连接上工作
常用指令
指令名 | 功能 | 说明 |
CAPABILITY | 请求服务器支持的功能列表 | 无参数 |
NOOP | 更新服务器的一些状态 | 无参数 |
LOGOUT | 注销登陆 | 无参数 |
STARTTLS | TLS认证登陆 | 无参数 |
AUTHENTICATE | SASL认证登陆 | 无参数 |
LOGIN | 用户名密码登陆 | 用户名 密码 |
SELECT | 登陆成功后选中一个邮箱 | 邮箱名 |
EXAMINE | 以只读方式选中一个邮箱 | 邮箱名 |
CREATE | 创建邮箱 | 邮箱名 |
DELETE | 删除邮箱 | 邮箱名 |
RENAME | 重命名一个已存在的邮箱 | 已存在邮箱名 新邮箱名 |
SUBSCRIBE | 用来在客户机的活动邮箱列表中增加一个邮箱 | 邮箱名 |
UNSUBSCRIBE | 用来从活动列表中去掉一个邮箱 | 邮箱名 |
LIST | 用于列出邮箱中已有的文件夹 | 邮箱路径参数BASE:表示用户登陆目录;第二个参数template:表示希望显示的邮箱名 |
LSUB | 显示那些使用SUBSCRIBE命令设置为活动邮箱的文件 | 邮箱路径和邮箱名 |
STATUS | 查询邮箱的当前状态 | 多参数 |
APPEND | 上传一个邮件到指定的Folder(文件夹/邮箱)中 | <folder><attributes><date/time><size><mail data> |
CHECK | 用来在邮箱设置一个检查点,类似NOOP | 无参数 |
CLOSE | 当前被选中邮箱中永久删除带有/Deleted标记位的所有邮件,并从被选中状态返回至认证状态 | 无参数 |
EXPUNGE | 从当前被选中邮箱中永久删除带有/Delted标记位的所有邮件 | |
SEARCH | 根据搜索条件在处于活动状态的邮箱中搜索邮件,然后显示匹配的邮件编号 | [CHARSET specification] (search criteria) 字符集标志参数[CHARSET specification]由CHARSET和注册的字符集标志符组成,缺省的标志符是US-ASCⅡ,所以该参数长省略。search criteria:查询条件参数,明确查询的关键字和值 |
STORE | 用于修改指定邮件的属性,包括给邮件打上已读标记、删除标记,等等 | |
COPY | 复制指定邮件到特定目标邮箱的末尾 | 序列集,邮箱名 |
UID | 以制定UID的方式去使用其他IMAP命令 | IMAP命令 该命令参数 |
fetch | 获取邮件的相关数据 | 序列集,邮件数据项名称或者宏 |
工作流程
- 1) 客户端向服务器发送tcp连接请求,完成tcp三次握手
- 2) 客户端向服务器发送capability命令,服务器进行响应,返回支持的功能列表;
- 3) 客户端向服务器发送LOGIN命令,其中包含登录用户的用户名、密码,服务器回复ok,登录成功;备注:使用imap协议时,客户端向服务器发送的用户名和密码是明文的。
- 4) 客户端向服务器发送LIST命令,邮件服务器返回详细的文件夹列表;
- 5) 客户端向服务器发送LSUB命令,邮件服务器返回订阅的邮箱地址列表;
- 6) 客户端向服务器发送NOOP命令,与服务器保持连接,可以随时获取新邮件或者消息状态更新;
- 7) 客户端向服务器发送STATUS命令,邮件服务器返回指定邮箱文件夹的状态,下图显示收件箱状态ok;还会获取其他文件目录的状态
- 8) 客户端向服务器发送SELECT命令,选择inbox文件夹
- 9) 客户端向服务器发送FETCH命令,来检索与消息相关数据(如获取正文),
- 10) 客户端向服务端发送UID命令,服务器返回用于fetch的UID列表;
- 11) 客户端获获取完邮件后,将会结束连接,执行四次tcp关闭连接。
示例介绍
- Connect:
telnet <IP> 143
openssl s_client -connect mail.qq.com:993 -crlf
- Login/Logout:
A01 LOGIN username password
A01 OK LOGIN completed.
A01 LOGOUT
* BYE Microsoft Exchange Server 2013 IMAP4 server signing off.
A01 OK LOGOUT completed.
- Capability:
A capability
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=NTLM AUTH=GSSAPI UIDPLUS MOVE ID XPROXY3 CHILDREN IDLE NAMESPACE LITERAL+
A OK CAPABILITY completed.
- Folder:
//CREATE <folder>
//CREATE可以创建指定名字的新邮箱。邮箱名称通常是带路径的文件夹全名。(有些IMAP客户机使用邮件夹称呼新邮箱)
A003 CREATE owatagusiam/
A003 OK CREATE completed.
A004 CREATE owatagusiam/blurdybloop
A004 OK CREATE completed.
//DELETE <folder>
//DELETE命令删除指定名字的文件夹。文件夹名字通常是带路径的文件夹全名,当邮箱被删除后,其中的邮件也不复存在。
A683 DELETE blurdybloop
A683 OK DELETE completed.
A684 DELETE foo
A684 NO Name "foo" has inferior hierarchical names
A685 DELETE foo/bar
A685 OK DELETE Completed.
//RENAME <old folder><new folder>
//RENAME命令可以修改文件夹的名称,它使用两个参数:当前邮箱名和新邮箱名,两个参数的命名符合标准路径命名规则。
C: A683 RENAME blurdybloop sarasoop
S: A683 OK RENAME completed
C: A684 RENAME stuff/junk newbox
S: A684 OK RENAME Completed
- List of Folder:
//All Folder
A02 LIST "" *
* LIST (\HasChildren) "/" Folder
* LIST (\HasNoChildren) "/" Folder/Folder_1
* LIST (\HasNoChildren) "/" Folder/Folder_2
* LIST (\HasNoChildren) "/" &T797Og-
* LIST (\Marked \HasNoChildren) "/" &g0l6Pw-
* LIST (\HasNoChildren) "/" &U9FO9nux-
* LIST (\HasNoChildren) "/" &V4NXPpCuTvY-
* LIST (\HasChildren) "/" &gFR8+066-
* LIST (\HasNoChildren) "/" &TvtSoQ-
* LIST (\HasNoChildren) "/" &ZeWLsA-
* LIST (\HasNoChildren) "/" &ZeVThg-
* LIST (\Marked \HasNoChildren) "/" INBOX
* LIST (\Marked \HasNoChildren) "/" &XfJT0ZABkK5O9g-
* LIST (\Marked \HasNoChildren) "/" &XfJSIJZkkK5O9g-
A02 OK LIST completed.
//Children Folder:
A04 LIST "Folder" *
* LIST (\HasChildren) "/" Folder
* LIST (\HasNoChildren) "/" Folder/Folder_1
* LIST (\HasNoChildren) "/" Folder/Folder_2
A04 OK LIST completed.
//Like Folder:
A05 LIST "" "Fol*"
* LIST (\HasChildren) "/" Folder
* LIST (\HasNoChildren) "/" Folder/Folder_1
* LIST (\HasNoChildren) "/" Folder/Folder_2
A05 OK LIST completed.
- LSUB
//SUBSCRIBE <mailbox>
//SUBSCRIBE命令用来在客户机的活动邮箱列表中增加一个邮箱,该命令只有一个参数,希望添加的邮箱名。
A114 SUBSCRIBE new/anotherbox
A114 OK SUBSCRIBE completed
//UNSUBSCRIBE <mailbox>
//UNSUBSCRIBE命令用来从活动列表中去掉一个邮箱,一个参数:希望去掉的邮箱名。
A115 UNSUBSCRIBE new/anotherbox
A115 OK SUBSCRIBE completed
//LSUB <folder><mailbox>
//LSUB命令修正了LIST命令,LIST返回用户$HOME目录下所有的文件,但LSUB命令只显示那些使用SUBSCRIBE命令设置为活动邮箱的文件。两个参数:邮箱路径和邮箱名。
A116 LSUB “” *
* LSUB () “/” stuff/junk
* LSUB () “/” neebox
* LSUB () “/” new/anotherbox
A116 OK LSUB completed
- Status
A status inbox (messages)
* STATUS INBOX (messages 1051)
A OK STATUS completed.
B STATUS INBOX (MESSAGES UNSEEN RECENT)
* STATUS INBOX (MESSAGES 1051 UNSEEN 0 RECENT 0)
B OK STATUS completed.
- Select Folder:
A03 SELECT INBOX
* 1051 EXISTS
* 1 RECENT
* FLAGS (\Seen \Answered \Flagged \Deleted \Draft $MDNSent)
* OK [PERMANENTFLAGS (\Seen \Answered \Flagged \Deleted \Draft $MDNSent)] Permanent flags
* OK [UIDVALIDITY 14] UIDVALIDITY value
* OK [UIDNEXT 14260] The next unique identifier value
A03 OK [READ-WRITE] SELECT completed.
- CLOSE
//CLOSE命令表示Client结束对当前Folder(文件夹/邮箱)的访问,关闭邮箱该邮箱中所有标志为、DELETED的邮件就被从物理上删除。CLOSE没有命令参数。随后可以SELECT另一Folder。
A341 CLOSE
A341 OK CLOSE completed
- Search:
//All uid
A01 Search ALL
* SEARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
A01 OK SEARCH completed.
//Recent uid
A02 Search NEW
* SEARCH 1052 1053
* 2 RECENT
A02 OK SEARCH completed.
- Fetch:
//flags
A01 fetch 1:* FLAGS
* 1 FETCH (FLAGS (Seen))
* 2 FETCH (FLAGS (Seen))
* 3 FETCH (FLAGS (\Seen \Answered))
A01 OK FETCH complete.
//internal date
A02 fetch 1:* INTERNALDATE
* 1 FETCH (INTERNALDATE "13-Jun-2012 11:04:18 +0200")
* 2 FETCH (INTERNALDATE "20-Aug-2012 16:29:21 +0200")
...
* 22 FETCH (INTERNALDATE "23-Oct-2012 15:31:05 +0200")
A02 OK FETCH complete
//uid
A03 fetch 1:* UID
* 1 FETCH (UID 32)
* 2 FETCH (UID 124)
* 3 FETCH (UID 165)
A03 OK FETCH completed.
//see more
A04 fetch 1:10 (UID FLAGS INTERNALDATE)
* 1 FETCH (UID 32 FLAGS (\Seen) INTERNALDATE "29-Aug-2017 17:32:54 +0800")
* 2 FETCH (UID 124 FLAGS (\Seen) INTERNALDATE "30-Sep-2017 12:09:21 +0800")
* 3 FETCH (UID 165 FLAGS (\Seen) INTERNALDATE "30-Sep-2017 17:29:21 +0800")
A04 OK FETCH completed.
//Header of index 5
A06 Fetch 5 full
* 5 FETCH (INTERNALDATE "27-Jun-2006 14:00:27 +0800" FLAGS (/Seen) ENVELOPE ("Tue, 27 Jun 2006 13:56:51 +0800" "test " (("xxxxxx" NIL "xxxx" "xxxxxx")) (("xxxxxx" NIL "xxxx" "xxxxxx")) (("xxxxxx" NIL "xxxx" "xxxxxx")) ((NIL NIL "xxx" "xxxxx")) NIL NIL NIL "<000f01c699ae$7c5014a0$6b01a8c0@xxxxxx.xx >") BODY (("text" "plain" ("charset" "gb2312") NIL NIL "base64" 14 2) ("text" "html" ("charset" "gb2312") NIL NIL "base64" 420 7) "alternative") RFC822.SIZE 1396)
A06 OK Fetch completed.
//Index 5 completed content
A07 Fetch 5 rfc822
* 5 FETCH (RFC822 {1396}
....
A07 OK Fetch completed.
//Index 5 flags
* 5 FETCH (FLAGS (\Seen))
* 3 RECENT
A08 OK FETCH completed.
//Header
A09 fetch 1 body[header]
* 1 FETCH (BODY[HEADER] {1316}
Return-Path: <rmsbox@test1.priv>
... email ...
A09 OK FETCH complete.
//index range header
A10 fetch 1:* body[header]
Return-Path: <rmsbox@test1.priv>
... email ...
Return-Path: <rmsbox@test1.priv>
... email ...
Return-Path: <rmsbox@test1.priv>
... email ...
A09 OK FETCH complete.
//Show(from、to、subject、date)
A10 fetch 1:1 (body[header.fields (from to subject date)])
* 1 FETCH (BODY[HEADER.FIELDS (from to subject date)] {183}
From: IT <IT@xxx.net>
To: AllStaff <AllStaff@xxx.net>
Subject:
=?gb2312?B?udjT2rmry77Tyrz+zfi52L38xtq/qsb0U1BGvMfCvLzssum5psTczajWqg==?=
Date: Tue, 29 Aug 2017 17:30:40 +0800
FLAGS (\Seen))
A10 OK FETCH completed.
//Showing subject
a fetch 1:1 (body[header.fields (subject)])
* 1 FETCH (BODY[HEADER.FIELDS (subject)] {88}
Subject:
=?gb2312?B?udjT2rmry77Tyrz+zfi52L38xtq/qsb0U1BGvMfCvLzssum5psTczajWqg==?=
FLAGS (\Seen))
a OK FETCH completed.
- Noop:
A01 noop
A01 OK NOOP completed.
- Set
a store 1:* +flags seen ... set read all emails
a store 1:* -flags seen ... set unread all emails
a store 10:100 +flags seen ... set as read emails from 10 to 100 (meaning as UID range)
a store 22 +flags deleted ... set as deleted email 22 (meaning as UID 22)
a store 22 -flags deleted ... retore, undelete ... email 22 (meaning as UID 22)
//STORE <mail id><new attributes>
//STORE 命令用于修改指定邮件的属性,包括给邮件打上已读标记、删除标记,等等。STORE命令当前只有两个数据项类型可用,FLAGS:表示邮件的一组标志; FLAGS.SLIENT,表示一组邮件的标志,通过在两种数据项前加上加号或者减号可以进一步改变它们的执行情况,加号表示数据项的值添加到邮件中,减号表示将数据项的值从邮件中删除。
A003 STORE 2:4 +FLAGS (\Deleted)
* 2 FETCH FLAGS (\Deleted \Seen)
* 3 FETCH FLAGS (\Deleted)
* 4 FETCH FLAGS (\Deleted \Flagged \Seen)
A003 OK STORE completed
- EXPURGE
Emails wich are set as “deleted” are actually still present in “trash” folder.
If you need to delete them you have to run “EXPURGE” command.
A01 expunge
* 2 EXPUNGE
A01 OK EXPUNGE complete.