电子邮件基础

  上个世纪七十年代,电子邮件从实验室中诞生,随着网络技术的发展和普及,电子邮件在上世纪八十年代迎来了大爆发,逐渐称为一种主流的通讯工具,在即时通讯工具出现以前,电子邮件占领了网络通讯的主流  上个世纪七十年代,电子邮件从实验室中诞生,随着网络技术的发展和普及,电子邮件在上世纪八十年代迎来了大爆发,逐渐称为一种主流的通讯工具,在即时通讯工具出现以前,电子邮件占领了网络讯的。   在聊邮件传输协议之前,我专门去百度和谷歌上去找了一下关于电子邮件的定义,百度百科给出的定义是:电子邮件是一种利用电子手段提供信息交换的通讯方式,同时包括文字,图像,声音等多种方式。维基百科说:Electronic mail is a method of exchanging messages between people using electronic devices. 电子邮件最初的目的是科学工作者交流的工具,ISOC在RFC821,822等文件中定义了一系列协议标准。

电子邮件基本原理:

  电子邮件是通过电子邮件服务器完成信息传递的工具,主要包括收和发两个过程,RFC821 文件中定义了简单邮件传输协议(Simple Mail Transfer Protocol)负责发送邮件,RFC1939定义了POP3协议标准,RFC3501定义了IMAP4rev1协议,主要负责接收电子邮件,随着网络的发展,通过网页收发邮件成文了一种主流,使用超文本传输协议(Http)。

电子邮件的主要特点是:

   1..传播速度快, 2.便捷, 3.成本低, 4,应用广(受众广) 5,信息多样化, 6,安全。   电子邮件的服务主要是由电子邮件服务商提供,大型邮件服务一般是自主开发,或者基于现有的系统做二次开发,主流的邮箱服务器主要由以下两个系统

.基于unix/Linux开发的

   1.sendmail(SMTP),devecot(pop3)    2.基于Postfix/Qmail

基于Windows平台的邮件系统

   1.Exchange    2.Lotus Domino(IBM)    3.Scalix    4Zimbra    5.MDeamon   (针对邮件系统的攻击:1.针对邮件内容的盗取。2。对系统的破坏)

.简单邮件协议(Simple Mail Transfer Protocol,SMTP)

注:RFC821首先说明,SMTP是一个高效的,可靠的邮件传输协议,思考:为什么是高效且可靠的协议。 简单邮件传输协议是邮件发送协议,有TCP25号端口提供服务。

SMTP过程:

  1用户发出SMTP请求-> 发送SMTP与接收SMTP之间建立一条双向通道,->SMTP发送者发送MAIL命令,指明邮件发送者->若SMTP接收者可以接受邮件,则返回OK应答,->SMTP发送者再发出RCPT命令,确认邮件是否收到。SMTP接收者可以接受则返回OK->若不能接收到则发出拒绝接收应答,->重复,当接收者收到全部邮件后接受到特备序列,托成功处理了有邮件则返回OK。

若接收方与发送方连接再同一个传送服务下时,邮件可以直接由发送方主机传送到接收方主机,不在统一服务下时,则通过SMTP中转。 SMTP过程: 1. 基本发送过程   mail   smtp的发送动作有三步

  • mail开始给出发送者的标识    mail from:<reverse-path>    该命令要求接收服务器复位状态表,清空缓冲区,给出一个反向路径,以便进行错误信息的反馈。若请求被接收,则返回 250 OK。其中<reverse-path>包括主机和源邮箱的反向路由,其中的第一个主机就是发送此命令的主机。

  1. 发送RCPT命令   RCPT TO:<froward-path>     向前路径标识接收者,命令被接受则返回并存储向前路径,若接收者未知则返回一个550 failure(该命令可能会执行多次,知道超时或成功)

  2. DATA   若命令被接受,返回一个354 Intermediate,并认定以下各行都是信件内容,信件结尾并收到存储后返回 250 OK.     必须指明,邮件内容结尾 <CRLF>.<CRLF> (邮件结束符)   使用SMTP发送一封简单的邮件,主要就是以上三个命令,首先标明发送人,其次指出发送目的,也就是邮件的接收者,最后使用DATA命令对邮件的内容进行编写,除了最基本的邮件发送命令外,RFC821文档中还规定了许多拓展功能,“VREY”用于确认用户名,其响应包括用户的命名和用户的邮箱;“EXPN” 参数是邮箱列表,相应包括所有列表中用用的命名和他们的邮箱。

***(笔者在看到这两个命令的时候用telnet链接多个邮件服务商的SMTP服务器尝试去使用这个命令,但尝试了很多次,一直报错,查阅众多资料,终于在CSDN博主@aifeier1982 SMTP的相关命令中找到答案: VRFY 确认在邮件传递过程中可以使用的邮箱,该命令在Exchange实现中默认关闭,之后在诸多文章中也找到了相关字眼,邮件服务商为保证服务的安全,”EXPN“和”VRFY“默认状态下是关闭的。)***

  “用户名”是一个多余的项目,它是故意被加上,若主机采用“VRFY”和“EXPN”命令,最后本地邮箱必须提供用户名使其被主机确认。在一些主机中,邮箱列表和一个邮箱的代名词有一点不清楚,一般数据结构可能包括两种类型的接口,若要发出确认,则一定要给出确定响应。   

   RFC821中还给出了发送和获得两个动作的定义,称将邮件发送到用户的邮箱称之为发送信件,送至用户的终端称为获得信件,在整个SMTP过程当中,“用户代理”,“SMTP服务器”作为SMTP过程中的节点完成了信件发送的全部过程,在后面会提到关于整个SMTP的逻辑过程。在这里按照笔者的理解,发送信件是发送者终端通过自己的SMTP服务器想接收者SMTP服务器发送信件的过程,而获得信件是SMTP服务器向用户推送信件的过程,SMTP整个过程是一个推的动作,在许多主机中,获得信件和发送信件功能上十分类似,所以被同事放在了SMTP中,以下三个命令被定义来支持获得信件。
       SEND FROM:<REVERSE-PATH>
  SOML FROM:<REVERSE-PATH>
  SAML FROM:<REVERSE-PATH>

  send和mail命令要求邮件内容直接发送到终端上,但不知道为什么,按照RFC821 中规定的命令,甚至按照后面的例子尝试使用send命令腾讯企业邮箱一直反馈的是命令参数错误,笔者暂时还没有找到一个合适的答案。

  前文中提到,SMTP过程主要涉及到两个角色:”SMTP client“(以下简称用户)和”SMTP server“(以下简称服务器),用户使用SMTP协议发送电子邮件,首先要和SMTP建立一个TCP链接,通过用户代理向服务器发送”HELLO“,若同意链接,服务器返回一个成功的信号,然后登录认证,用户账密认证成功以后,发送邮件,

telnet smtp.exmail.qq.com 25 
220 smtp.qq.com Esmtp QQ Mail Server
helo 1
250 smtp.qq.com
auth login
334 VXNlcm5hbWU6
 username(base64)  // SMTP登录时,通过base64编码后传输
334 UGFzc3dvcmQ6
password(base64)
235 Authentication successful
mail from<shaochanghong@zorelworld.com>
501 Syntax: MAIL FROM: <address>
mail from :<from@mailserver.com>
250 Ok
rcpt to:<forward-path@mailserver.com>
250 Ok
data
354 End data with <CR><LF>.<CR><LF>
from:shao
to:cahgn
subject:test
                        //邮件头和邮件体之间有空行
This iss a test email
/
.
250 Ok: queued as
quit
221 Bye

下图为一次简单的邮件发送产生的SMTP流量包

笔者通过Telnet和腾讯企业邮箱SMTP服务器建立链接,通过抓包可清晰的看出TCP三次握手过程,如下图所示:

 

值得一提的是,通过telnet链接SMTP服务器,每键入一个字符,都会直接发送到服务器端,也就是说,使用telnet发送邮件,不存在输入错误删除的动作。下图所示为从建立SMTP开始到发出“HElO 1”命令结束所有的TCP数据包。当用户与服务器建立链接,服务器向用户发送220消息,确认链接建立,客户端代理立即回复ACK消息,随后输入“helo 1”六个ASCII字符,得到服务器的六次响应

电子邮件服务器主要完成三个动作,发送,接收,转发,早期的电子邮件只能发送ASCII标识的字符,随着网络技术的发展随后引入了不同的编码规则,RFC2045-RFC2049 定义了MIME规则,来规定电子邮件中,非ASCII码字符,附件,图片等信息的表述方式。

SMTP命令说明

SMTP定义了邮件传输或由用户定义邮件传输或由用户定义的系统功能。他的命令是由<CRLF>结束的字符串 发送邮件的命令操作涉及到不同的数据对象,由不同的参数相互连接。回复路径就是MAIL命令的参数,转发路径就是RCPT命令的参数,邮件日期是DATA后的参数。这些参数或命令对象必须跟在命令后,这种模式也就要求不同的缓冲区来存储这些对象。

“helo”接收、确认和发送SMTP “mail"开始将邮件发送到一个或多个邮箱中, (回复路径可以是一个或者多个邮箱 "RCPT" 转发路径


eg:

  1. Mail from:<one> rcpt to:@two,@three,@four

    1. 2 mail from:<one,two>

 rcpt to:<@three,@four>

3 mail from:<one,two three> rcpt to:<four>


上面这个例子是多次转发的一个过程,由用户1,经由用户2,3,向用户4发送信件。

“data":接收者将跟在命令行后的行为作为邮件内容,此命令导致命令后的邮件内容加入邮件内容缓冲区。邮件内容缓冲区可以包括128个ASCII字符<crlf>.<crlf>是邮件内容结束符。要求接收者马上处理保存邮件内容,此过程将回复路径缓冲区和邮件内容缓冲区的内容全部清空,如果操作成功,则返回OK

220 smtp.qq.com Esmtp QQ Mail Server
helo 1
250 smtp.qq.com
auth login
334 VXNlcm5hbWU6
username(base64)
334 UGFzc3dvcmQ6
Password(base64)
235 Authentication successful
MAIL FROM:<SHAOCHANGHONG@ZORELWORLD.COM
250 Ok
RCT                //命令错误返回命令错误码 501.
501 Error: malformed authentication response
RCPT TO:<SHAOCHANGHONGQWER@126.COM
250 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
FROM:SHAO
TO:tIAN
data:wed, 31 may 2021 05:15:22
subject:Test
​
This is a test email
.
250 Ok: queued as
 

ABCONNECT TCP220 smtp…………server(SMTP)auth login334 Vx……USERNAME (BASE64)334 ug.....PASSWORD(BASE64)235 AUTHENTICATION SUCCESSFULMAIL FROM:<USERNANE@MAILSERVER>250 OKRCPT TO:<FORWRAD-PATH>250 OKDATA354 END.....DATA(END WITH "<CRLF>.<CRLF>")250 OKQUIT250 OKAB

其中data标记之后,在邮件头中使用”data“能够标记时间,该标记并非必须,若没有标记则时间为1970年。

 

SMTP发送邮件至少需要了解的命令: ”HELO“,”MAIL FROM", "RCPT TO", "DATA", "RSET", 一个清除命令,用于取消发送操作,执行该命令,将清空缓冲区所有内容,不做任何操作。 “NOOP":NOOP命令是一个空操作,服务器的返回值永远是成功的操作,但是,在服务器返回NOOP响应前,会将未响应的操作响应后,再响应NOOP。 ”QUIT“退出操作,断开用户代理和SMTP服务器之间的连接。

透明性: 通常用户并不关注非法序列的输入,而SMTP服务器将这些操作,做了一个透明性的保证。

  • 在发送邮件之前,发送SMTP必须检查邮件的每一行,如果是一个句号,就在行首加一个句号

  • 当邮件被接收时,接收SMTP必须检查邮件的每一行,有一个呼号,中止,有两个句号则删除第一个。

发送的邮件可以包括128个ASCII码,所欲字符发送到收信者的邮箱,包括格式符号和其他控制字符。如果传输信道提供一个八位数据流,7位ASCII码就可以在其中传输,将最高位置零。 一些对象需要最大和最小的大小限制,也就是说,每一个实现必须能够接收大于最小大小,小于最大大小的对象,不能发送不符合规定区间大小的邮件。下面时SMTP规定的邮件大小限制:


用户名:64字节 路径:256字节 命令行:512字节 应答行:512字节 文本:1000个字符 接收缓冲区:100个接收者


对于邮件服务器来说HELO命令是非必须的(网易,腾讯提供的SMTP服务是必须要有HELO命令的,但参数并没有特殊要求) 下面是SMTP服务器常见的返回消息类型


501 参数格式错误 502 命令不可实现 503 错误的命令序列 504 命令参数不可实现 211 系统状态或系统帮助响应 214 帮助信息 220 <domain>服务就绪 221 <domain>服务关闭 421 <domain>服务未就绪,关闭传输信道 250 要求的邮件操作完成 251 用户非本地,将转发向<forward-path> 450 要求的邮件操作未完成,邮箱不可用 550 要求的邮件操作未完成,邮箱不可用 451 放弃要求的操作;处理过程中出错 551 用户非本地,请尝试<forward-path> 452 系统存储不足,要求的操作未执行 552 过量的存储分配,要求的操作未执行 553 邮箱名不可用,要求的操作未执行 354 开始邮件输入,以"."结束 554 操作失败


POP3

Post office protocol version3 被定义在TCP110端口上 对于在网路上比较小的节点,支持消息传输系统(MTS,Messages Transfer System)是现实的,但这样的节点支持邮件管理也是有用的。

pop3过程

初始时,服务器通过侦听110号端口开始POP3服务,当客户机需要使用服务时,他将与服务器主机建立TCP连接,当连接建立后,POP3发送确认消息,客户端与服务器相互(分别)交换命令和响应,这一过程一直持续到连接结束。

关于POP3

POP3的命令有一个命令标识和一些参数组成,以<CRLF>对结束,命令由ASCII码组成,命令一般3-4个字母,参数可达40个字符。 POP3响应由一个状态码和一个可能跟信息的命令组成,所有的响应也是由<CRLF>对结束 POP3是一个邮件管理协议,SMTP协议是一个邮件发送协议,有客户端代理通过SMTP协议,向SMTP服务器将邮件推送过去,再由SMTP服务器推送向目标用户的SMTP服务器。而POP3协议则是一种邮件管理,在用户与服务器建立TCP连接后,将邮件服务器端的所有数据拉取到本地,值得注意的是,在POP3将邮件全部拉取到本地之后,邮件服务器中将不在存放邮件,对邮箱中邮件的所有处理也都将在本地进行。

POP3命令

USER username 认证用户名 PASS password 认证密码认证,认证通过则状态转换 APOP name,digest 认可一种安全传输口令的办法,执行成功导致状态转换,请参见 RFC 1321 。 STAT 处理请求 server 回送邮箱统计资料,如邮件数、 邮件总字节数 UIDL n 处理 server 返回用于该指定邮件的唯一标识, 如果没有指定,返回所有的。 LIST n 处理 server 返回指定邮件的大小等 RETR n 处理 server 返回邮件的全部文本 DELE n 处理 server 标记删除,QUIT 命令执行时才真正删除 RSET 处理撤消所有的 DELE 命令 TOP n,m 处理 返回 n 号邮件的前 m 行内容,m 必须是自然数 NOOP 处理 server 返回一个肯定的响应 QUIT 希望结束会话。如果 server 处于"处理" 状态,则现在进入"更新"状态,删除那些标记成删除的邮件。如果 server 处于"认可"状态,则结束会话时 server 不进入"更新"状态 。

POP3的响应类型较少 +OK 成功 -err 失败

 

使用命令行连接POP3服务器进行登录操作时,与SMTP不同的是,POP3邮件用户名和密码不在是BASE64编码,直接输入明文即可。 通常情况来说,当本地对邮件操作之后,只会在本地操作,只有在发出quit命令之后,客户端与pop3服务器才会断开连接,将本地操作同步到远程服务器端。 邮局协议在邮件管理过程中,将所有邮件拉取到本地进行操作,远程服务器端不在存储数据,倘若没有断开连接,将不能在其余机器上操作使用邮箱,带来了极大的不便。

如图所示是POP3一次连接过程抓包数据。 如图:一次POP3连接。

IMAP协议

Internet Message Access Protocol:因特网邮件访问协议,允许一个客户端访问和操作在一个服务器上的电子邮件,IMAP4re1允许以一种功能上等效于本地本舰加的方式操作邮箱(远程邮件文件夹)。一个离线客户端与服务器异步(交互)。IMAPrev1包括创建,删除以及重命名邮箱,检查新邮箱,永久删除邮件,设置和清楚标记操作,RFC2822和RFC2045解析,检索,及选择性的获取邮件属性,文本及其中的一部分。IMAP4rev1中的邮件通过使用数字访问。这些数字或者邮件序列号或者是唯一标识符。 IMAP协议不同于pop协议,他是通过与邮件服务器之间建立可靠链接,通过命令与服务器进行交互,在服务器端对邮件进行操作。

IMAP假定了类似于TCP协议提供了可靠的数据流,使用TCP时,IAMP监听143号端口,定义在RFC3501中。

一次IMAPrev1链接组成有:一次客户端,服务器端的网络的建立,服务器的初始欢迎,以及客户端和服务器的交互。由客户端命令服务器完成结果响应。

客户端命令引发操作,每一个客户端命令以一个标识作为前缀,称之为标签,客户端为每个命令行生成一个标签。

有时客户端没有描述一个完整的命令,有两种情况, 1.一个命令参数被另一个命令参数所引用, 2.命令参数要求服务器反馈 若服务器发现命令的一个错误,他就发送一个带有匹配命令的标签的BAD完整响应,以拒绝该命令

邮件属性

RFC3501中定义了邮件的属性,除了邮件文本,每个邮件都有一些与其相关的属性。这些属性可以被单独收回,或者与其它属性、或者邮件文本组合。

  • 邮件号 IMAP4rev1的邮件通过两个数值中的一个访问:唯一标识符,或者邮件序列号。

    • 唯一标识符(UID)的邮件属性。 分配给每一个邮件的32位值,和唯一标识符的值(见下)形成一个64位的值,这个值永远不能指向这个邮箱中的其它任何邮件,或者它后面的同名邮 箱。分配时,邮箱中的唯一标识符严格地按升序排列;每个邮件添加至邮箱时,它将被派予一个比它先加进来的邮件的唯一标识符更大的唯一标识符。与邮件序列号 不同,唯一标识符可以是不连续的。 在会话存活期,一个邮件的唯一标识符不能改变,也不应该在不同会话间改变。唯一标识符在不同的会话间改变必须使用给唯一标识符校验机制审查。永久唯一标识符要求客户端刷新其状态,以区别于与服务器的前面一个会话。

    • 邮件序列号的邮件属性 邮箱中,从1到邮件总数的一个相对位置。这个位置必须是按升序排序了的唯一标识符。每当新的邮件被加进来,它就被分配一个比它加进来之前该邮箱中的邮件总数大1的邮件序列号。在会话存活期,邮件序列号可以重新分配。

  • 标记的邮件属性。 与邮件相关联的一个0串或者已命名的符号串。向该串中新增时,设置一个标记,从该串中删除时,清除该标志。IMAP4rev1中有两种标记。两种标记的实例都可以是永久化的,或者会话化的。 系统标记是指在本文档中预告确定的。所有的系统标记以“/”开头。一些系统标记(/Deleted和/Seen)在其它地方的描述中有特殊的语义。目前定义的系统标记有: /Seen 邮件已读 /Answered 邮件已回复 /Flagged 邮件标记为紧急或者特别注意。 /Deleted 邮件为删除状态。 /Draft 邮件未写完(标记为草稿状态)。 /Recent

  • 实际日期的邮件属性

  • RFC2822 的大小邮件属性

  • 信封结构的邮件属性

  • 主题结构的邮件属性

  • 邮件文本 状态和流程图 一旦客户端和服务器间的连接建立完成,一个IMAP4rev1连接就会处于4种状态中的某一种。初始状态在服务器的欢迎中标识。大多数命令只在 特定的状态中才是正确的。当连接处于不适当的状态时,客户端尝试一个不适当的命令引发协议错误,服务器将以一个BAD或者NO(取决于服务器的实现体)命 令完成结果响应。 3.1. 未认证状态 在未认证状态下,大多数命令在得到许可前,客户端必须提供认证证书。若非连接已经是预认证了的,一个连接开始时,就进入了未认证状态。 3.2. 认证状态 在认证状态下,客户端是认证了的,它必须先于影响邮件的命令被许可前,选择一个邮箱以访问。当一个预认证连接开始,被认可的认证证书已经提供,选择一个邮箱发生错误后,或者一个成功的CLOSE命令后,就进入了认证状态。 3.3. 选中状态 在一个选中状态,一个邮箱被选中以访问。当一个邮箱被成功选中时,就进入了这个状态。 3.4. 注销状态 在注销状态下,连接正在被终止。一个客户端请求(通过LOGOUT命令),或者客户端、服务器的单方面动作,都会导致进入这个状态。 如果客户端请求注销状态,服务器必须在关闭连接前发送LOGOUT命令的一个非标签化BYE响应和一个标签化OK响应;客户端在关闭连接前,必须读取这个LOGOUT命令的标签化OK响应至。 在没有发送一个包含原因的、非标签化BYE响应的情况下,一个服务器不能单方面关闭连接。一个客户端不应单方面关闭连接,而应当发出一个LOGOUT命令。如果服务器发现客户端单方面关闭了连接,服务器可以忽略这个非标签化BYE响应,并简单地关闭它的连接。


     

    +———————-+ |connection established| +———————-+ || // +————————————–+ | server greeting | +————————————–+ || (1) || (2) || (3) // || || +—————–+ || ||

     

    +—————–+ || || || (7) || (4) || || || // // || || +—————-+ || || | Authenticated |<=++ || || +—————-+ || || || || (7) || (5) || (6) || || || // || || || || +——–+ || || || || |Selected|==++ || || || +——–+ || || || || (7) || // // // // +————————————–+ | Logout | +————————————–+ || // +——————————-+ |both sides close the connection| +——————————-+

    (1)未预认证的连接(OK欢迎) (2)预认证的连接(PREAUTH欢迎) (3)被拒绝的连接(BYE欢迎) (4)成功LOGIN或者AUTHENTICATE命令 (5)成功的SELECT或者EXAMINE命令 (6)CLOSE命令,或者失败的SELECT、EXAMINE命令 (7)LOGOUT命令,服务器关闭,或者连接已关闭

IMAP4rev1 操作的考虑

邮箱的命名

邮箱名是七位的。客户端实现体不能试图创建八位的邮箱名,应该吧“LIST”或者“LSUB”返回的任意八位邮箱名解释为“UTF-8”服务器实现体应当机制八位邮箱名的创建,LIST或者LSUB不应当返回八位的邮箱名。

不区分大小写的邮箱名“INBOX”是一个特殊的邮箱名被保留下来,表示该服务器上使用的主邮箱。又有其他邮箱名的解释都是依赖于实现体的。

特别的,文本档未指定是否区分被INBOX邮箱名的大小写。一些服务器实现体全部区分大小写;一些服务器实现体保留创建的邮箱名的大小写状态,而其他的则是不区分大小写的;还有一些服务器实现体则强制命名为特定形式。客户端实现体必须与其中的任何一种做好交互。如果一个服务器实现体吧非INBOX邮箱名解释为不区分大小写的,则它必须特别使用国际命名约定。

创建一个新的邮箱名, 有一些客户端的考虑: 1) 原语类(参见正式语法一节) 的任意一个字符要求邮箱名表述为一个引用字 符串或者原义字符串。 2) CTL 和其它生僻字符很难表述在用户界面, 所以最好避免。 3) 虽然通配符列表字符(“%” 和“*” ) 在邮箱名中是正确的, 但是因为与通 配符的解释相冲突, 所以很难把 LIST 和 LSUB 命令用于这样的邮箱名。 4) 通常, 保留一个字符(取决于服务器实现体) 用于层级分隔。 5) “#” 和“&” 这两个字符有约定语上的意义, 应当避免以其它意义使用它。

国际邮箱命名规则

按照约定,IMAP4rev1的国际邮箱名用UTF-7中所描述的UTF-7编码的修订版本描述。

客户端命令

客户端命令的任意状态命令

capability

参数: 无 响应: 请求非标签化响应: CAPABILITY 结果: OK-capability 完成 BAD-未知命令, 或者参数无效 CAPABILITY 命令请求服务器支持的功能列表。 在(标签化) OK 响应之前, 服务 器必须发送一个非标签化的、 带有“IMAP4rev1” 作为其功能列表之一的 CAPABILITY 响应。

NOOP

参数: 无 响应: 此命令无特定响应(见下) 结果: OK-noop 完成 BAD-未知命令, 或者参数无效 NOOP 命令总是成功的。 它什么也不做。

logout

参数: 无 响应: 要求非标签化的响应: BYE 结果: OK-logout 完成 BAD-未知命令, 或者无效参数 LOGOUT 命令告知服务器, 客户端准备关闭连接。 服务器必须在(标签化) OK 响 应前, 发送一个 BYE 非标签化响应, 并随后关闭这个网络连接。

客户端命令-未认证状态

starttls

参数: 无 响应: 此命令无需特定响应 结果: OK-starttls 完成, 开始 TLS 对话 BAD-未知命令, 或者无效参数 在来自服务器端的标签化 OK 响应末尾的 CRLF 之后, 一个“TLS” 对话就开始了。 一旦一个客户端发出一个 STARTTLS 命令, 它就不能再发送其它命令, 直到服务 器响应出现并且“TLS” 对话结束。一旦“TLS” 开始, 客户端必须丢弃关于服务器功能的缓存信息, 且应当重新发 出 CAPABILITY 命令。 这对保护免受修改功能列表指向 STARTTLS 的中间者攻击是 有必要的。 服务器可以在 STARTTLS 后发出不同功能。

authenticate

参数: 认证机制名 响应: 可请求的连续数据 结果: OK-authenticate 完成, 当前为认证状态 NO-authenticate 失败: 不支持的认证机制, 被拒绝的证书 BAD-未知命令, 或者无效参数, 认证对话被取消

login

参数: 用户名 密码 响应: 此命令无特定响应 结果: OK-login 完成, 当前是认证状态 NO-login 失败: 用户名或者密码被拒绝 BAD-未知命令, 或者无效参数 LOGIN 命令向服务器确认客户端, 并带有确认该用户的简单文本型密码。

注意: 在一个不安全网络(比如因特网) 上使用 LOGIN 命令有安全风险, 因为任 何网络传输的监控者都可以获取简单文本型密码。 LOGIN 命令不应当使用, 除非 作为最后一种方法, 同时, 建议客户端实现体采取措施使 LOGIN 命令的任何自动 使用无效。

客户端命令-认证状态

在认证状态下,把邮箱作为原语实体来操作的命令是允许的。在这些命令中,SELECT及EXMINE命令将会选中一个邮箱以访问及进入选中状态。除了常见的命令(capability,noop,logout),以下命令在认证状态下也是正确的:select,examine,create,delete,rename,subscribe,unsubscribe,list,lsub,status,append。

select

参数: 邮箱名 响应: 要求非标签化的响应: FLAGS, EXISTS, RECENT 要求 OK 非标签化响应: UNSEEN, PERMANENTFLAGS, UIDNEXT, UIDVALIDITY 结果: OK-select 完成, 当前是选中状态 NO-select 失败, 当前是认证状态: 不存在这个邮箱, 不能访问邮箱 BAD-未知命令, 或者参数无效

EXAMINE

参数: 邮箱名 响应: 要求非标签化响应: FLAGS, EXISTS, RECENT 要求 OK 非标签化响应: UNSEEN, PERMANENTFLAGS, UIDNEXT, UIDVALIDITY 结果: OK-examine 完成, 当前是选中状态 NO-examine 失败, 当前是认证状态: 没有这个邮箱, 不能访问邮箱 BAD-未知命令, 或者无效参数

CREATE 命令 参数: 邮箱名 响应: 此命令无需特定响应 结果: OK-create 完成 NO-create 失败: 不能创建这个名称的邮箱 BAD-未知命令, 或者无效参数

RENAME 命令 参数: 已经存在的邮箱名 新的邮箱名 响应: 此命令无需特定响应 结果: OK-rename 完成 NO-rename 失败: 不能重命名邮箱为这个名称, 不能以这个名称重命名至邮箱 BAD-未知命令, 或者无效参数

SUBSCRIBE 命令 参数: 邮箱 响应: 此命令无需特定 结果: OK-subscribe 完成 NO-subscribe 失败: 不能订阅这个邮箱名 BAD-未知命令, 或者无效参数

SUBSCRIBE 命令增加指定邮箱名至服务器的活动邮箱序列或者订阅邮箱序列中, 通过 LSUB 命令返回。 当且仅当订阅成功时, 该命令返回一个标签化的 OK 响应。 服务器可以向 SUBSCRIBE 证实邮箱参数以确保它的存在。 但是, 它不能单方面从 订阅列表中删除一个存在的邮箱名, 即使该邮箱名不存在了。

UNSUBSCRIBE 命令 参数: 邮箱名 响应: 此命令无需特定响应 结果: OK-unsubscribe 完成 NO-unsubscribe 失败: 不能取消订阅该邮箱名 BAD-未知命令, 无效参数 UNSUBSCRIBE 从服务器的活动邮箱序列或者订阅邮箱序列中删除特定邮箱名, 通 过 LSUB 命令返回。当且仅当取消订阅成功时, 该命令返回一个标签化的 OK 响应。

LUSB

参数: 引用名, 带有可能的通配符的邮箱名 响应: 非标签化的响应: LSUB 结果: OK-lsub 完成 NO-lsub 失败: 不能列出那个引用或者名称 BAD-未知命令, 或者无效参数 LSUB 命令返回的是, 用户已经声明为活动的、 或者订阅了的名称序列的一个名 称子集。 0 个或者更多的非标签化 LSUB 答复被返回。 LSUB 的参数同于 LIST 的形 式。

STATUS 命令 参数: 邮箱名, 状态数据项名 响应: 非标签化响应: STATUS 结果: OK-status 完成 NO-status 失败: 没有那个名称的 status BAD-未知命令, 或者无效参数

APPEND 命令 参数: 邮箱名, OPTIONAL 位的组合列表, OPTIONAL 日期/时间串, 邮件原义 响应: 此命令无特定响应 结果: OK-append 完成 NO-append 错误: 不能添加到该邮箱, 标记、 或者日期/时间、 或者邮件文本有 错误 BAD-未知命令, 或者无效参数

在被选中状态, 操作一个邮箱中邮件的命令是被允许的。 除了全局命令(CAPABILITY, NOOP, 及 LOGOUT) , 及认证状态命令 (SELECT, EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRI BE, LIST, LSUB, STATUS, 及 APPEND) , 在被选中状态时以下命令也是有 效 的: CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, 及 UID。

CHECK 命令 参数: 无 响应: 此命令无需特定响应 结果: OK-check 完成 BAD-未知命令, 或者无效参数 CHECK 命令请求当前被选中邮箱的一个检查站。 一个检查站指向每个取决于实现 体的、 与邮箱相关联的(例如, 以邮箱在硬盘中的状态, 决定它在服 务器上的 内存中的状态) 、 并不是作为每个命令的一部分进行常规执行的内部事务。 一个 检查站可以完成实时的非瞬时数量。 如果一个服务器实现体没有这些内部事 务 的考虑, CHECK 等效于 NOOP。 一个 EXISTS 非标签化响应作为 CHECK 的一个结果发生, 这是不一定的。 NOOP, 而不是 CHECK, 应当用于新邮件的投票。 例子: C: FXXZ CHECK S: FXXZ OK CHECK Completed

CLOSE 命令 参数: 无 响应: 此命令无需特定响应 结果: OK-close 完成, 当前是认证状态 BAD-未知命令, 或者无效参数 CLOSE 命令从当前被选中邮箱中永久删除带有/Deleted 标记位的所有邮件, 并从 被选中状态返回至认证状态。 没有非标签化 EXPUNGE 响应被发送。 如果邮箱通过 EXAMINE 命令被选中, 或者用别的方法以只读方式选中, 则没有邮 件会被删除, 也不会报错。 甚至, 一个邮箱被选中, 没有预先发送一个 CLOSE 命令, 一个 SELECT, EXAMINE, 或者 LOGOUT 命令就可以被发出。 SELECT, EXAMINE, 及 LOGOUT 命令没有进行删除, 就暗暗关闭了当前被选中的邮箱。 然而, 当很多邮 件被删除时, 一个 CLOSE- LOGOUT 或者 CLOSE-SELECT 序列比一个 EXPUNGE-LOGOUT 或者 EXPUNGE-SELECT 快得多, 因为没有非标签化 EXPUNGE 响应(客户端可以适 当忽略) 被发送。

EXPUNGE 命令 参数: 无 响应: 非标签化响应: EXPUNGE 结果: OK-expunge 完成 NO-expunge 失败: 不能删除(例如, 没有权限) BAD-未知命令, 或者无效参数 EXPUNGE 命令从当前被选中邮箱中永久删除带有/Delted 标记位的所有邮件。 在 返回一个 OK 到客户端前, 每个被删除的的邮件会引发一个非标签化的 EXPUNGE 响应被发送。 例子: C: A202 EXPUNGE S: * 3 EXPUNGE S: * 3 EXPUNGE S: * 5 EXPUNGE S: * 8 EXPUNGE S: A202 OK EXPUNGE complted 注意: 在这个例子中, 邮件3 , 4 , 7 , 及1 1 带/Deleted 标记位。 进一步的 解释参看 EXPUNGE 响应的描述。

SEARCH 命令 参数: OPTIONAL [CHARSET]声明, 检索准则(一个或者多个) 响应: REQUIRED 非标签化响应: SEARCH 结果: OK-search 完成 NO-search 错误: 不能检索该[CHARSET]或者准则 BAD-未知命令, 或者无效参数 SEARCH 命令检索邮箱以获取符合给定准则的邮件。 检索准则由一个或者多个检 索关键词组成。 来自服务器的非标签化 SEARCH 响应由符合检索准则的邮件相应 的邮件序列号列表组成。 当多个关键词被声明时, 结果是匹配这些关键词的所有邮件的交集(并起效) 。 例如, 准则 DELETED FROM “SMITH” SINCE 1-Feb-1994 指向来自 Smith 的、 自从1 9 9 4 年2 月 1 日开始存放于邮箱中的所有被删除的邮件。 一个检索 关键词也可以是一个或者多个检索关键词的一个组合列表(例 如, 使用 OR 和 NOT 关键词) 。 服务器实现体可能拒绝接受带有终端内容媒体类型的[MIM-IMB]主体部分, 而接 受 TEXT 和 SEARCH 匹配集相应的 MESSAGE。 OPTIONAL [CHARSET]声明由其后紧跟着一个注册了的[CHARSET] 的字 “CHARSET” 组成。 它表示, 出现在检索准则中 的字符串的[CHARSET]。 在以 [CHARSET]而不是 US-ASCII 比较文本之前, [MIME-IMB]内容转换编码, 及在[RFC- 2822]/[MIME-IMB]头部的[MIME-HDRS]字符串, 必须被解码。 US-ASCII 必须受支 持; 其它的[CHARSET]s 可能受支 持。 如果服务器不支持声明了的[CHARSET], 它必须返回一个标签化的 NO 响应(而不 是一个 BAD) 。 该响应应当包含 BADCHARSET 响应码, 该响应码可能列出受服务 器支持的[CHARSET]s。 在字符串形式的所有检索关键词里, 如果该字符串是该范围的一个子串, 则邮件 符合该关键词。 匹配是不区分大小写的。 已定义的检索关键词如下。 参数的准确语法定义参看正式语法一节。 <sequence set> 带有已声明的邮件序列号集相应的邮件序列号的邮件。 ALL 邮件中所有邮件; ANDing 的默认初始关键词。 ANSWERED 带有/Answered 标记位的邮件。 BCC <string> 在信封结构的 BCC 域包含有指定字符串的邮件。 BEFORE <date> 实际日期(忽视时间和时区) 早于指定日期的邮件。 BODY <string> 在邮件的主体域包含有指定字符串的邮件。 CC <string> 在信封结构的 CC 域包含有指定字符串的邮件。 DELETED 带有/Deleted 标记位的邮件。 DRAFT 带有/Draft 标记位的邮件。 FLAGGED 带有/Flagged 标记位的邮件。 FROM <string> 在信封结构的 FROM 域包含有指定字符串的邮件。 HEADER <field-name> <string> 带有一个含指定 field-name([RFC-2822]中定义) 的头部、 且在该头部(它跟 在 colon 之后) 的文本中包含指定字符串的邮 件。 如果将要检索的字符串(参 数中的 string) 长度为零, 那么, 它将匹配带有一个含指定 field-name、 内容 可有可无的头部行的所有邮件。 KEYWORD <flag> 带有指定关键词标记位的邮件。 LARGER <n> 带有一个[RFC-2822](定义) 的、 大于指定字节数的大小的邮件。 NEW 带有/Recent 标记位, 但不带有/Seen 标记的邮件。 它在功能上等效于 “(RECENT UNSEEN) ” 。 NOT <search-key> 不符合指定检索关键词的邮件。 OLD 不带有/Recent 标记位的邮件。 它在功能上等效于“NOT RECENT” (与 “NOT NEW” 相反) 。 ON <date> 实际日期(忽视时间和时区) 在指定日期的邮件。 OR <search-key1> <search-key2> 符合任意一个检索关键词的邮件。 RECENT 带有/Recent 标记位的邮件。 SEEN 带有/Seen 标记位的邮件。 SENTBEFORE <date> [RFC-2822]Date: header(忽视时间和时区) 早于指定日期的邮件。 SENTON <date> [RFC-2822]Date: header (忽视时间和时区) 在指定日期的邮件。 SENTSINCE <date> [RFC-2822]Date: header (忽视时间和时区) 在指定日期或者晚于指定日期 的邮件。 SINCE <date> 实际日期(忽视时间和时区) 在指定日期或者晚于指定日期的邮件。 SMALLER <n> 带有一个[RFC-2822]的、 小于指定字节数大小的邮件。 SUBJECT <string> 在信封结构的 SUBJECT 域含有指定字符串的邮件。 TEXT <string> 在邮件的头部或者主体含有指定字符串的邮件。 TO <string> 在信封结构的 TO 域含有指定字符串的邮件。 UID <sequence set> 带有指定唯一标识符集相应的唯一标识符的邮件。 序列集顺序排列是允许的。 UNANSWERED 不带有/Answered 标记位的邮件。 UNDELETED 不带有/Deleted 标记位的邮件。 UNDRAFT 不带有/Draft 标记位的邮件。 UNFLAGGED 不带有/Flagged 标记位的邮件。 UNKEYWORD <flag> 不带有指定关键词标记位的邮件。 UNSEEN 不带有/Seen 标记位的邮件。 例子: C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM “Smith” S: * SEARCH 2 84 882 S: A282 OK SEARCH completed C: A283 SEARCH TEXT “string not in mailbox” S: * SEARCH S: A283 OK SEARCH completed C: A284 SEARCH CHARSET UTF-8 TEXT {6} C: XXXXXX S: * SEARCH 43 S: A284 OK SEARCH completed 注意: 因为本文档限制于7 位 ASCII 文本, 所以不可能显示真的 UTF-8 。 “XXXXXX” 可能是实际处理中的8 位数据的6 个字节。

FETCH 命令 参数: 序列集, 邮件数据项名称或者宏 响应: 非标签化响应: FETCH 结果: OK-fetch 完成 NO-fetch 错误: 不能获取该数据 BAD-未知命令, 或者无效参数 FETCH 命令获取邮箱中的一个邮件的相关数据。 被获取的数据项可以是一个原 语, 或者一个组合列表。

 

STORE 命令 参数: 序列集, 邮件数据项名称, 邮件数据项值 响应: 非标签化响应: FETCH 结果: OK-store 完成 NO-store 错误: 不能保存该数据 BAD-未知命令, 或者无效参数 STORE 命令修改邮箱中邮件相关的数据。 正常地, STORE 将返回数据更新后的值 和一个非标签化 FETCH 响应。 数据项名称中的“. SILENT” 后缀保护该非标签化 FETCH, 且服务器应当假定客户端已经自行决定了该更新后的值, 或者客户端不 关心该更新后的值。 注意: 不管是否使用了“. SILENT” 后缀, 如果发现一个邮件的标记有源于外部 资源的改变, 服务器应当发送一个非标签化 FETCH 响应。 目的是使标记的状态在 没有竞争的情况下确定。 现在已经定义了的、 可以保存的数据项有: FLAGS <flag list> 用参数替代邮件(不是/Recent) 的标记。 返回标记集的新值, 就像那些标记集 的 FETCH 结果一样。 FLAGS. SILENT <flag list> 等效于 FLAGS, 但是不会返回一个新值。 +FLAGS <flag list> 增加参数至邮件的标记集中。 返回标记集的新值, 就像那些标记集的 FETCH 结果 一样。 -FLAGS <flag list> 从邮件的标记集中删除参数。 返回标记集的新值, 就像那些标记集的 FETCH 结果 一样。 -FLAGS. SILENT <flag list> 等效于-FLAGS, 但是不会返回一个新值。 例子: C: A003 STORE 2: 4 +FLAGS (/Deleted) S: * 2 FETCH (FLAGS (/Deleted /Seen) ) S: * 3 FETCH (FLAGS (/Deleted) ) S: * 4 FETCH (FLAGS (/Deleted /Flagged /Seen) ) S: A003 OK STORE completed

COPY 命令 参数: 序列集, 邮箱名 响应: 此命令无需特定响应 结果: OK-copy 完成 NO-copy 错误: 不能复制那些邮件, 或者复制到那个名称 BAD-未知命令, 或者无效参数 COPY 命令复制指定邮件到特定目标邮箱的末尾。 在拷贝件中, 邮件的标记和实 际日期应当被保存, 且 Recent 标记应当被设置。 如果目标邮箱不存在, 服务器应当返回一个错误。 它不应当自动创建邮箱。 除非 确实不能创建目标邮箱, 否则服务器必须发送响应码 “[TRYCRETAE]” 作为标签 化 NO 响应的文本前缀。 这暗示客户端, 它可以尝试一个 CREATE 命令, 并且如果 CREATE 成功, 它可以重试 COPY。 如果 COPY 命令因为某种原因不能成功, 服务器实现体必须恢复目标邮箱状态到 COPY 尝试之前的状态。 例子: C: A003 COPY 2: 4 MEETING S: A003 OK COPY completed

UID 命令 参数: 命令名, 命令参数集 响应: 非标签化响应: FETCH, SEARCH 结果: OK-UID 命令完成 NO-UID 命令错误 BAD-未知命令, 或者无效参数 UID 命令有两种形式。 在第一种形式中, 它的参数是一个带有相应的一些适当参 数的 COPY, FETCH, 或者 STORE 命令。 不过, 参数序列中的数字是唯一标识符, 而不是邮件序列号。 序列集是许可的, 但是有可能唯一标识符不是连续的。 一个不存在的唯一标识符将被忽略, 而不会产生任何错误信息。 一个 UID FETCH 命令可能只返回一个 OK, 没有任何数据; 一个 UID COPY 或者 UID STORE 可能 只返回一个 OK, 没有任何操作。 在第二种形式中, UID 命令的参数是一个带有 SEARCH 命令参数的 SEARCH 命令。 这些参数的解释同于它们仅仅跟着 SEARCH; 但是, 一 个 UID SEARCH 命令的一 个 SEARCH 响应返回的数字是唯一标识符, 而不是邮件序列号。 例如, 命令 UID SEARCH 1: 100 UID 443: 557 返回的是, 邮件序列的数字队列 1: 100, 及 UID 队列 443: 557, 这两个序列集的交集相 应的唯一标识符。 注意: 在上面的例子中, 出现了 UID 队列 443: 557。 一个不存在的唯一标识符会 被忽略, 而不会产生任何错误信息, 同样的解释也适用于此。 因此, 即使 UID443 或者 557 不存在, 这个队列也是有效的, 且可以包含一个存在的 UID495。 还要注意, 一个 UID 队列 559: 永远包括邮箱中最末邮件的 UID, 即使 559 大于 已分配的任何 UID 值。 这是因为一个队列的内容独立于队列末点的顺序。 因此, 以作为一个末点的任意 UID 队列表示至少一个邮件(该邮件的 UID 是最大的) , 除非这个邮箱是空的。 一个非标签化 FETCH 响应中的“*” 后的数字永远是一个邮件序列号, 而不是一 个唯一标识符, 甚至对于一个 UID 命令响应也是如此。 然而, 服务 器实现体必 须隐式地包括 UID 邮件数据项作为一个 UID 命令引发的任意 FETCH 的响应部分, 不管一个 UID 是否被指定为一个到 FETCH 的邮件数据项。 注意: 包括一个 UID 邮件数据项作为一个 FETCH 的响应部分, 这个规则主要适用 于 UID FETCH 和 UID STORE 命令, 包括一个不含 UID 作为一个邮件数据项的 UID FETCH 命令。 尽管其它 UID 命令不太可能引发一个非标签化的 FETCH, 但是 这个规则也适用于这些命令。 例子: C: A999 UID FETCH 4827313: 4828442 FLAGS S: * 23 FETCH (FLAGS (/Seen) UID 4827313) S: * 24 FETCH (FLAGS (/Seen) UID 4827943) S: * 25 FETCH (FLAGS (/Seen) UID 4828442) S: A999 OK UID FETCH completed

X<atom>命令 参数: 已定义的实现体 响应: 已定义的实现体

结果: OK-命令完成 NO-失败 BAD-未知命令, 或者无效参数 任何以一个 X 为前缀的命令都是一个试验命令。 不属于本文档、 本文档的标准修 正版或者一个 IESG 认证的试验标准的一部分的命令, 必须用 X 作为前缀。 任何增加的、 一个试验命令引发的非标签化响应也必须以一个 X 作为前缀。 服务 器实现体不能发送任何这样的非标签化响应, 除非客户端通过发出关联的试验命 令来请求它。

IMAP 协议中的命令晦涩难懂,之后我将会单独写一篇文章讨论关于IMAP协议命令的相关使用说明。(小声逼逼:其实就是我现在还没弄明白)

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 CentOS 7 中部署电子邮件服务器通常涉及到安装和配置邮件服务软件,比如 Postfix 作为邮件传输代理(MTA)和 Dovecot 或 Exim 作为邮件用户代理(MUA)。以下是一个简化的步骤指南: 1. **安装基础软件包**: - 更新系统并安装必要的软件包: ``` sudo yum update -y sudo yum install -y epel-release mailx postfix ``` 2. **配置 Postfix**: - 创建一个新的邮局主机记录(MX): ``` sudo vi /etc/postfix/main.cf ``` - 添加或修改 `main.cf` 文件,确保 `myhostname` 和 `mydomainname` 设置正确,然后添加 MX 记录指向服务器的 IP。 3. **启动并设置 Postfix**: - 启动 Postfix 服务: ``` sudo systemctl start postfix ``` - 检查 Postfix 是否运行正常,并设置为开机启动: ``` sudo systemctl enable postfix ``` 4. **配置 Dovecot (可选)**: - 安装 Dovecot: ``` sudo yum install dovecot-imapd dovecot-lmtpd dovecot-pop3d ``` - 配置文件位于 `/etc/dovecot/conf.d/90-mail.conf` 等,调整权限和设置以适应需求。 5. **创建用户和邮箱**: - 使用 `useradd` 命令添加新用户,同时设置密码: ``` sudo useradd -d /var/spool/mail/$username -s /bin/bash $username sudo passwd $username ``` 6. **配置用户邮件箱**: - 编辑 Dovecot 的用户配置文件,允许它们访问自己的邮箱: ``` sudo vi /etc/dovecot/conf.d/10-mail.conf ``` 7. **防火墙配置**: - 开放必要的端口,如 25 (SMTP), 587 (submission), 143 (IMAP), 993 (IMAP over TLS), 110 (POP3), 和 995 (POP3 over TLS)。使用 firewall-cmd 或者 firewalld 服务。 8. **安全性和认证**: - 可能需要设置 SSL/TLS 安全连接,以及设置密码策略、授权等。 9. **测试配置**: - 使用 telnet 或者 mailx 测试 SMTP 和 IMAP 连接。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

望晓天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值