子郵件協議中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小時內與您取得聯系。