子邮件协议中POP3协议用于接收邮件,SMTP协议用于发送邮件。SMTP的全称为Simple Mail Transfer Protocol,也就是简单邮件传输协议,字如其名。
相较于POP3而言,SMTP确实比较简单。这里的简单并不是指SMTP的命令比POP3少,而是指SMTP的命令是有序的,而POP3的命令是无序的,理解这一点很重要。也就是说SMTP的命令是要组合在一起才能完成一次邮件发送任务,单独调用每个命令的意义不大。POP3命令则不同,LIST、STAT、UIDL、TOP、RETR、DELE等命令都可以独立使用,比如用LIST命令查看邮件清单,然后用RETR命令接收邮件。
简单的另一层含义是:就socket编程而言实现发送数据要比实现接收数据简单点。
比如接收数据时要判断数据是否接收完毕。如果一条数据以回车换行结束,就需要判断是否接收到了"\r\n",从而确保读取到一条完整的消息体。而发送数据则不需要考虑上述问题,你可以按照自己的节奏发送数据,可以一次将整个消息体发送出去,也可以不用考虑服务器的死活一个字节一个字节发送数据,直至将整条消息发送完毕。
换句话说,接收数据要以流的方式进行,而不是简单的开辟一个缓冲区,进行一次recv操作。 虽然大部分情况下这种方式也没有问题,比如写个Demo程序,但如果要让你的网络程序非常健壮的话,最好以流的方式进行读取。因为并不是每次对方都会按照你期望的方式发送数据给你,比如,你开辟了1024字节缓冲区用于接收网络数据,但对方可能一次只给你发送一个字节,或者发出了1025个字节。
SMTP和HTTP协议一样都属于请求应答式协议,也就是一问一答,客户端发送命令后,服务器返回响应内容。 SMTP的响应格式和HTTP协议的基本一样,都是响应码+响应描述。响应码用三位数字表示,空格后则是响应信息的描述,只是HTTP协议会多一个版本信息。
这种一问一答式协议,在HTTP协议上体现的并不是很明显,只有HTTP连接设置为Keep-Alive时,你才有机会使用GET或POST命令反复与服务器进行交互,否则只有一次问答的机会。
但在SMTP协议下这种一问一答的交互方式就非常明显了。 主要原因是完成一次邮件的发送任务涉及到的步骤比较多,我把电子邮件的发送分为如下五个步骤:
1、建立会话;
2、身份认证;
3、发送邮件信封(发件人和收件人);
4、发送邮件内容(邮件正文和附件);
5、关闭会话;
SMTP的命令主要就分布在这五个步骤中。下面以网易的yeah邮箱(smtp.yeah.net服务器)为例,具体说明这五个步骤的实现。C代表客户端,S代表服务端。
SMTP命令:HELO
该阶段用于建立客户端与SMTP服务器的连接,在此基础上,双方进行友好的问候。SMTP服务器的默认端口号是25,如果是支持SSL协议,则默认端口号是465。如果采用的是STARTTLS协议,则默认端口是587,所谓的STARTSSL其实就是SSL协议,只是开始会话前双方客套一下,问一下对方你还支持SSL啊?
连接建立后,服务器会发送一条欢迎语。接着你就需要问候一下服务器,并带上你的机器的名称。如下:
S: 220 yeah.net Anti-spam GT for Coremail System (yeah[20141016])
C: HELO your-computer-name
S: 250 OK
SMTP命令:AUTH LOGIN
该命令用于进行身份验证,虽然这一步在SMTP协议中不是强制的要求,但目前几乎所有的SMTP服务器都需要进行身份认证。增加这一步可以大大减少垃圾邮件的存在,以及避免有人伪造其它发件人进行邮件的发送操作。
这一步中账号和密码需要进行base64编码,包括服务器发来的提示信息也是base64编码。
首先发送AUTH LOGIN命令,服务器会返回“334 XNlcm5hbWU6”,“dXNlcm5hbWU6”解码后为“username:”
UGFzc3dvcmQ6解码为"Password:"
也就是提示用户输入用户名和密码。认证成功后返回235,注意返回的不是二百五(250)哦。 接着根据服务器返回的提示,发送账号(发件人的邮箱账号)和密码。
C: AUTH LOGIN
S: 334 dXNlcm5hbWU6
C: base64编码后的账号(发件人的邮箱账号)
S: 334 UGFzc3dvcmQ6
C: base64编码后的密码
S: 235 Authentication successful
至于为何是base64编码,可能是SMTP协议设计时考虑到用户名和密码的重要性,所采用的最简单的“加密”手段。虽然base64只是编码方式,不是加密方式,但在早期控制台输入命令的情况下,别人还是一下无法像记住明文一样记住这些无规律的base64编码。不过随着SSL的应用,这些都已不重要了。
SMTP命令:MAIL FROM、RCPT TO
该阶段是告诉服务器发件人和收件人的邮箱地址,可以把这个阶段想象为你在写纸质信件的信封。MAIL FROM用于指定发件人邮箱,该邮箱地址其实就是上述身份认证中的账号,如:
MAIL FROM: <lig4961@yeah.net>
RCPT TO用于指定收件人邮箱,一次只能指定一个收件人地址,如果收件人有多个的话,可以多次发送RCPT TO命令。
C: MAIL FROM: <lig4961@yeah.net>
S: 250 Mail OK
C: RCPT TO: <syfzxm@163.com>
S: 250 Mail OK
C: RCPT TO: <lig4961@yeah.net>
S: 250 Mail OK
注意,邮件地址要用放入<>中,此外,每条命令发送完毕后,一定要判断服务器返回码是否是250。 如果返回的不是二百五,说明你发送的地址可能是二百五,也就是不正确的地址,比如邮件地址中没有@,或者在同一个邮箱系统中,SMTP服务器发现收件人的地址并不存在,也就是没有注册过。
看到这里可能有人会有疑问:我们通过邮件客户端或网页写邮件时,不是有三种身份的收件人么?即:主送人(to)、抄送人(cc)、密送人(bcc)。是否存在RCPT CC和RCPT BCC命令,用于发送抄送人和密送人的邮箱地址呢?很遗憾,没有这两个命令。也就是说抄送人(cc)和密送人(bcc),也是通过RCPT TO命令进行发送。
既然发送时不区分,那么我们在收到的邮件中怎么还能看到主送人和抄送人呢?或者说如何做到让密送人在收到的邮件中看不见的。答案在下面邮件内容中。
SMTP命令:DATA
这一步是发送数据最多也是最复杂的一步,但操作命令却只有一个,就是DATA,也就是数据(邮件内容),邮件内容主要包括三个部分(可能会有内嵌资源文件,也可以理解为狭义上的附件):
1、邮件头;
2、邮件正文;
3、邮件附件;
DATA命令发送后,服务器会返回354响应码,并告诉客户端,数据结束要以"\r\n.\r\n"来标识。接下来客户端就可以发送整个邮件内容了。
DATA
354 End data with <CR><LF>.<CR><LF>
SUBJECT:=?UTF-8?B?5p2l6IeqU29mdGxlZe+8jOi/meaYr+S4gOWwgea1i+ivlemCruS7tg==?=FROM: <lig4961@yeah.net>
TO: 'softlee1' <syfzxm@163.com>, 'softlee2' <lig4961@yeah.net>
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="=NextPart_SOFTLEE_Mail_E0B1A829CB1D4f55A037AE04B6A72078"
--=NextPart_SOFTLEE_Mail_E0B1A829CB1D4f55A037AE04B6A72078
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgVHJhbnNpdGlvbmFs
Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXRyYW5zaXRpb25h
bC5kdGQiPg0KPGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPg0KDQo8
aGVhZD4NCiAgICA8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQv
邮件内容的格式目前基本都采用MIME格式,MIME格式比较简单,可参见文章:《如何解析EML(邮件)格式的文件以及一款小巧的EML邮件阅读工具》。
这里我们不具体介绍如何编码邮件正文和附件。主要介绍邮件头中的信息,主题(Subject)、发件人(From)、收件人(To)、抄送(Cc)。我们看查看邮件时,读到的主题、收件人和抄送人就来自于上述字段。这里收件人和抄送人仅作为邮件头的一部分进行展现,服务器并不会关心这些地址是否真实存在,或者说服务器并不关心这些地址是否跟使用RCPT TO命令发送的地址保持一致。回到第三阶段中最后的几个问题,我们可以通过邮件头来展现该邮件的抄送人是谁,并且将密送人隐藏掉。当然你也可以篡改上述信息,比如隐瞒某些收件人,或者将密送人也一并展现。
邮件正文和附件的编码可参照MIME格式的文章。最后所有数据发送完毕后,一定要发送"\r\n.\r\n",从而告诉SMTP服务器所有数据发送完毕。
SMTP命令:QUIT
这一步非常简单,就是发送一条QUIT命令,QUIT命令发送完毕后,还是要判断服务器的返回码是否为250。如果返回的不是,则表明发送失败,SMTP服务器可能不会将邮件转发到收件人所在的邮箱中,这一点很重要。
至此,整个SMTP协议介绍完毕。SMTP协议比较简单,但具体的实现细节可能还有很多,需要在实践中去体验,有的服务器返回消息体是多行的,比如outlook邮箱的服务器,下面是outlook邮箱使用STARTTLS协议截图:
附一: SMTP邮件发送工具
该工具特点:
1、基于命令行方式且只有一个独立文件;
2、支持SSL、STARTSSL协议;
3、具有丰富的命令行参数;
近被「诺亚财富34亿踩雷」的新闻刷屏了,报案、否认、甩锅,一波三折,如今演绎成了罗生门。承兴造假,京东否认,诺亚报案。如何通过技术方案的设计在风险发生时为业务提供强有力的举证支持是我最近一直在思考的事情,其中电子合同的有效性是我们一直在讨论的重点问题。
随着互联网金融/金融科技的发展,合同通过电子化签署逐渐被大家接受。但是受限制于国内《电子签名法》采用了技术折中的立法模式,法律法规仅从功能性和效果上的角度上提出了要求。
如何界定电子签名、数据电文及电子合同的有效性涉及较为复杂的技术知识,司法实践中对于技术路径审查的相关经验并不多,存在着对“电子签名制作数据”、“电子签名”、“数字签名”、“用户密码”等专业概念的认知偏差,对如何签出一份合法有效的电子合同则比较模糊。
针对于此,我也与很多的法务同学、电子合同服务商进行过交流,整理了下我在交流中的感受,分享出来抛砖引玉,欢迎砸我。
首先我们得确认电子合同是合法有效的,这是这篇文章的基础。
对于这一点,在《合同法》以及《电子签名法》中都有明确规定:
《中华人民共和国合同法》
第十条:当事人订立合同,有书面形式、口头形式和其他形式;
第十一条:书面形式是指合同书、信件和数据电文(包括电报、电传、传真、电子数据交换和电子邮件)等可以有形地表现所载内容的形式。
简而言之:电子合同属于合同的一种。
《中华人民共和国电子签名法》
第十三条 电子签名同时符合下列条件的,视为可靠的电子签名:
- 电子签名制作数据用于电子签名时,属于电子签名人专有;
- 签署时电子签名制作数据仅由电子签名人控制;
- 签署后对电子签名的任何改动能够被发现;
- 签署后对数据电文内容和形式的任何改动能够被发现。当事人也可以选择使用符合其约定的可靠的条件的电子签名;
第十四条 可靠的电子签名与手写签名或者盖章具有同等的法律效力
简而言之:《电子签名法》规定了可靠的电子签名的有效性以及可靠的电子签名的要素:专有、专控、不可篡改。
(当然,《电子签名法》中也规定了一些不适用电子签名的情况:涉及婚姻、收养、继承等人身关系的;涉及停止供水、供电、供气等公用事业服务的;法律、行政法规规定的不适用电子文书的其他情形。这些不在我们本次讨论范围之内。)
合同的成立在传统合同书中一般通过签字或者盖章的方式来体现,在电子合同中签字盖章的行为被可靠的电子签名所代替《电子签名法》第十四条[1]。
本质上电子合同的成立生效没有跳出传统合同的要件要求,这些要求我们不在此做讨论。
既然是「可靠的电子签名」与手写签名或者盖章具有同等的法律效力,那么我们只需要能在业务中能够证明符合相关要素即可。市面上的一些第三方电子合同服务商都有符合相关规定(至少是能经得起推敲)的产品方案(毕竟人家赚的就是这份钱)。
但第三方服务商的标准产品开发需要最大程度的降低其自身的风险,一般情况下会将签署合同的整个过程至于其可控范围内,其产品流程并不一定适合我们的业务系统交互需求甚至可能与业务系统相冲突。
因此部分过程需要业务系统自己完成,业务系统在风险发生时需要承担一定举证责任(不得不说,某些服务商的方案对于业务系统侵入性太大,很难接受啊)。
我们先对电子合同签署的生命流程进行拆解:
实名认证步骤,一般分为个人实名和企业实名。(不讨论线下核验的方式)
个人实名的方案很多:生物识别、银行卡验证、手机号实名认证……一般目前最保险的是扫脸认证活体检测,最好将活体的视频保存下来,以便举证。
企业实名,目前用的最多的营业执照、银行账户小额打款、法人身份证来验证。
这里顺便我说一句,我只看到一家供应商可以提供法人姓名+身份证号的认证信息,不知道市面上还有没有其他的服务商可以有此类服务提供(不是根据法人身份证对信息做二要素验证,而是根据工商注册信息对提供的法人姓名和身份证号做验证)。
意愿认证上,方式有很多。目前大部分第三方电子合同服务商都采用云托管数字证书模式,在意愿认证上针对个人一般采用短信验证码、人脸识别等来作为签署人意愿表达的行为;针对企业一般通过向企业授权人发送短信验证码、识别授权人人脸等方式或者采用 Ukey 来作为意愿表达。
这里多说一句:如果你采用 ukey 来做鉴权,需要考虑一点就是签署时使用的数字证书是否为 ukey 里存储的数字证书。如果不是(极大概率不是)一定要注意证据链完整的问题,因为本质上还是云托管数字证书来完成签署。
至于合同生成和司法举证,去找第三方服务商吧,如果这些事情都要自己做,那你就是自己在做一个电子合同平台了。
其实技术上没有难点,主要在举证问题上有一些思考:
一般来说,我们做实名都是调用第三方数据接口,我们需要尽量保证调用记录的完整性及可查性。在出现电子合同有效性问题时可以提供我方已经进行应尽的实名义务,并在力所能及的范围内做到了对用户的实名认证。
针对企业实名,要至少核验包括包括企业名称、统一社会信用代码,最好对法人姓名及身份证号进行核验,同时应对经办人进行个人实名核验,以及企业核心隐私数据的核验,例如对公银行打款、开具指定金额发票等核验方式;
也可通过电子认证服务机构颁发的数字证书进行实名核验(这一点某 CA 的一个服务可以实现通过全国大部分(小)银行发放的 ukey进行实名认证,不过大行很少)。
这里需要注意的一点是我们在选择第三方数据服务商的时候一定要主要选择政府权威部门的数据库或者取得政府权威部门授权或认可的电子数据库(比如国政通……国政通麻烦广告费结下)
在合法合规的前提下,除通过短信验证码、人脸识别或 ukey 认证等方式完成用户意愿认证外,管理系统还应该尽可能的收集用户在签署时的IP 地址、操作设备 MAC 地址、操作系统信息等可以佐证是用户自身操作的信息。
目前大部分系统对接第三方电子合同服务商的时候为了不让电子合同系统侵入业务系统都采用了各家服务商提供的「自动签署」方案(这一点我要吐槽下拉,各家差不多都有这样的接口,但是在使用上并没有很好的给用户说明。)
首先,我们要说的是《电子签名法》第十三条里提到的「签署时电子签名制作数据仅由电子签名人控制」这一项规定是对电子签名过程中电子签名制作数据归谁控制的要求。这里所规定的控制是指一种实质上的控制,即基于电子签名人的自由意志而对电子签名制作数据的控制。
在电子签名人实施电子签名行为的过程中,无论是电子签名人自己实施签名行为,还是委托他人代为实施签名行为,只要电子签名人拥有实质上的控制权,则其所实施的签名行为,满足本法此项规定的要求。(这段话不是我说的,是全国人大关于《电子签名法》的释法[2])
在中国互联网金融协会《互联网金融个体网络借贷电子合同安全规范(征求意见稿)》第 8 司法举证要求(d)中也提到「电子签名人委托他人代为实施签名行为时,从业机构或第三方电子合同订立系统服务商提供电子签名制作数据由电子签名人控制的证据,包括调用电子签名制作数据的时间和方式、电子签名人位置、IP地址、授权及认证方式、授权及认证记录等;」
所以,自动签署的方案大家还是可以放心用,只需要你能通过其他方式来证明电子签名人拥有实质上的控制权即可。
关于电子签名,有一个举证的坑。
《电子签名法》第二十八条:电子签名人或者电子签名依赖方因依据电子认证服务提供者提供的电子签名认证服务从事民事活动遭受损失,电子认证服务提供者不能证明自己无过错的,承担赔偿责任。
也就是说,关于电子签名,举证责任倒置。即对方提出的侵权事实,电子认证提供者如果予以否认,则应负举证责任,证明自己没有过错。
在司法实践上,《袁斌与合肥梦川玖贸易有限公司等小额借款合同纠纷二审案件》【案号:北京市第三中级人民法院(2018)京03民终4903号】[3]中,法院也是这样认定的。
当然,只要电子认证服务提供者能够证明自己对于电子签名人或者电子签名依赖方所遭受的损失没有过错,就不承担责任。而对于电子认证服务提供者来讲,只要能够证明其所提供的服务完全是严格按照本法和符合国家规定并向国务院信息产业主管部门备案的电子认证业务规则实施的,则应能够证明没有过错。(《电子签名法释义 法律责任》[4])
电子签名无效仅仅表示该电子签名并非当事人真实意愿的表达,并不必然影响当事人之间的部分关系(比如债权债务关系、劳动关系)的成立。
如果能够从其他方面来证明当事人之间存在相关关系,法院大概率上会要求侵权方承担民事责任。但一些合同上具体规定可能无法予以认定。
比如上边提到的《袁斌与合肥梦川玖贸易有限公司等小额借款合同纠纷二审案件》中,法院虽然认定电子签名无效,但是从实名认证信息、操作记录等方面认定借款合同有效。
其实这一点上,《最高人民法院关于互联网法院审理案件若干问题的规定》第十一条[5]已经明确指出:「当事人提交的电子数据,通过电子签名、可信时间戳、哈希值校验、区块链等证据收集、固定和防篡改的技术手段或者通过电子取证存证平台认证,能够证明其真实性的,互联网法院应当确认。」
最后多说一句,如果有钱花一点钱找服务商做个证据保全系统或者直接和司法鉴定中心、公证处之类的合作,毕竟法官不是开发小哥,你跟他讲技术远不如公证处或者司法鉴定中心的一个章子管用。
[1]
《电子签名法》第十四条:可靠的电子签名与手写签名或者盖章具有同等的法律效力。
[2]
全国人大关于《电子签名法》的释法:http://t.cn/AiYEl4bm
[3]
《袁斌与合肥梦川玖贸易有限公司等小额借款合同纠纷二审案件》【案号:北京市第三中级人民法院(2018)京03民终4903号】:http://t.cn/AiYEOrYd
[4]
《电子签名法释义 法律责任》:http://t.cn/AiYElv5w
[5]
《最高人民法院关于互联网法院审理案件若干问题的规定》第十一条:http://www.court.gov.cn/zixun-xiangqing-116981.html
互金业务中经常提到的电子合同,到底是个啥?
张小璋,公众号:张小璋的碎碎念(ID:SylvainZhang),人人都是产品经理专栏作家。野蛮生长的产品经理,专注于互联网金融领域。
本文原创发布于人人都是产品经理。未经许可,禁止转载。
题图来自 Unsplash,基于 CC0 协议
是案例解析 FileMaker 18 新功能的最后一篇,我们来聊一下用增强的“从 URL 插入”脚本来实现发送 HTML 邮件的功能。
发送邮件对于 FileMaker 来说并不是什么陌生功能,专门就有发送邮件这个脚本来操作。不过我们这里谈的是带排版的 HTML 邮件,这才是 FileMaker 18 新增的功能。这个功能的实现是因为“从 URL 插入”脚本新增支持:smb、smtp、smtps、ldap 和 ldaps。其中 smtp&smtps 就是发邮件的协议,前者为常规发件协议、后者为 SSL 加密的发件协议。比如,我们使用的 QQ 企业邮箱,就是通过 SSL 加密,所以必须使用 smtps 协议。
选定协议之后,我们还需要了解 cURL 发邮件的配置选项。这主要包括:
--mail-from:发件人邮箱
--mail-rcpt:收件人邮箱
--upload-file:包含发件人、收件人、标题、邮件内容的 txt 文件
--user:“发件邮箱:密码”格式的用户名和密码
以上配置需要连接成一条文本,设置到“从 URL 插入”的“指定cURL 选项”。
需要特别注意的是 --upload-file 选项,这里是将发件人、收件人、标题、邮件内容合并成一个 txt 文本,并放置到容器中进行调用。文本格式如下(Content-Type 和邮件内容之间需要留 1 行以上空行):
具备上面部分的知识后,我们来再看一下如何在 FileMaker 中实现。
我们主要会用的脚本就是“从 URL 插入”,它一共有 5 个配置项。
选择全部内容:这里是发送邮箱、不需要接收返回数据,所以勾不勾都不影响
以上就是 FileMaker 18 发 HTML 邮件的新功能。
*请认真填写需求信息,我们会在24小时内与您取得联系。