上次在《Email诞生记》说到小王和老周设计了电子邮件的系统, 但是不能支持附件 -- 这也是本文要解决的重点。
3
附件
小王回去后想了很久, 怎么才能给在邮件中加上附件呢? 邮件的正文是文本格式的, 但图片,word这些文件是二进制的,完全不同啊?
小王躺在床上翻来覆去很久才睡着, 甚至做了一个Email的梦 :-)
第二天小王找到了师傅老周讲了自己的困惑。
老周说: "我们搞计算机行业的,遇到问题解决方法通常有两个: 1. 增加一个抽象层 2. 分而治之。"
小王不满的心想: 这不等于什么都没有说嘛!
老周笑了:你想想, 我们把原始问题划分成两个子问题来解决: 1. 如何让邮件正文和附件区分开来。 2. 如何把二进制的数据加入到邮件中。
小王说: “第一个问题我觉得很简单, 在正文中画一道分隔线不就行了, 上面是正文 ,下面是附件”
“你犯了一个错误,小王, 你把计算机当成人了 , 其实计算机很笨,你需要精确的定义那个分隔线到底是什么, 我们还得精确的告诉计算机,这个邮件分为多个部分, 有些是正文,有些是附件”
小王不好意思的笑了: “的确是, 我们要不这样,先定义一个邮件的内容类型,例如Content-type=plain-text , 那这个邮件就是纯文本的, 如果Content-type=mixed, 就代表是有文本就有附件”
老周想了想说:“这样的话扩展性不好, 我们把Content-type 分为主类型/子类型, 像这样:”
老周说着在白板上画了起来:
Content-type = 主类型/子类型
其中主类型和子类型都可以扩展。
现阶段:如果主类型是Text , 那子类型可以是 plain, 代表纯文本, 也可以是别的东西, 现在我也不知道, 可以扩展。
如果主类型是Multipart , 就代表这个文件有多个部分组成, 那子类型可以是mixed, 即多个部分是混合的。
例如:
Content-type=text/plain : 这是个纯文本邮件
Content-type=multipart/mixed : 这是一个由正文和附件混合组成的邮件。
(码农翻身注: text 除了plain之外,还支持html , multipart 还支持alternative, related , 为了简化,这里不再展开 )
小王说:师傅你考虑的可真是长远啊, 但是这个文本和附件之间的分隔符怎么弄?
老周说: “我们可以让发邮件的客户端,像我们的Quickmail 自己来选择, 但是选择以后要告诉我们, 我想可以在Content-type后面加个分隔符的属性
Content-type=multipart/mixed;
boundary="----=_NextPart_AEDGREGREWGREWGFDSFGSGFDSFTTRFSGGFD_001_0051_01A";
只要这个boundary的属性和邮件中的数据不冲突就可以 。”
小王说:“我试着设计一个包含附件的正文, 师傅你看看。 ”
//定义这是一个混合的邮件, 每个部分的分隔符由boundary定义。 为了便于阅读, 我把这个boundary故意写的很简单, 实际复杂的多
Content-type=multipart/mixed;
boundary="--A001_0051_01A";
//以分隔符来开始邮件正文
----A001_0051_01A
//这是“为了庆祝产品发布, 今晚在海底捞聚餐”的base64编码的结果
5Li65LqG5bqG56Wd5Lqn5ZOB5Y+R5biD77yMIOS7iuaZmuWcqOa1t+W6leaNnuiBmumkkA==
----A001_0051_01A
Content-type:audio/wav
name:"fly.wav"
<这里是附件1的数据>
----A001_0051_01A
Content-type: image/jpg
name:"sky.jpg"
<这里是附件2的数据>
//整个邮件结束的标记
----A001_0051_01A
老周说: 怪不得老板夸你说你一点就透,果然是啊, 你都能想到给每个附件加个名称和类型了
“还是师傅你考虑的周到,这个Content-type可以随便扩展啊, 想写成啥写成啥。 那第二个问题:附件的内容怎么办? ”
“刚才你写那个邮件正文的base64编码的时候,没有给你启发吗? ”老周反问到
“啊,对了, 这些附件无非就是二进制的数据, 完全可以像处理汉字那样用base64来编码啊! 为了扩展性, 我们要不给每一个部分加一个编码类型的属性? 例如:”
Content-type: image/jpg
name:"sky.jpg"
encoding: base64
老周满意的说:“没问题,可以的”
4
扩展
小王和老周已经设计了一个收取邮件, 发送邮件的系统, 这个系统还可以支持附件。
在老周的带领下, 小王和其他同事经过几个月的时间把这个系统的客户端和服务器端开发了出来,经过同事的使用, 反响非常的好, 现在公司里每个人都可以快速的收发邮件了,工作效率有了极大的提升。
有一天老板的朋友来参观公司, 看到了这个神奇的系统,也立刻自己的公司部署了一套,包括一个QuickMail服务器和多个客户端, 发现真是好用。
Email 系统就这么一传十,十传百的传开了。
小王所在的MSHP公司仅仅靠出售QuickMail 系统,每年都活的非常滋润。
但是很快大家就遇到了一个问题: Email 在一个公司内运转的良好, 但是两个公司之之间还是没法发送邮件, 商务合作就不顺畅了。
小王想:既然我们的QuickMail 客户端和邮件服务器可以通过SMTP来通信 ,那两个邮件服务器之间是否也也可这么通信呢?
小王找到师傅提出了这个问题。
老周说:当然可以, 比方说吧, 有两个公司, 他们的邮件服务器分别是mailA.com 和 mailB.com , 当userA@mailA.com 给 userB@mailB.com发信的时候, 我们可以这么处理:
1. 用户userA通过SMTP把邮件发给mailA.com 这个邮件服务器
2. mailA.com 发现目标用户userB@mailB.com 并不在 自己的服务器上, 它就把信件暂时放到队列里。
3. mailA.com 从队列中取出邮件, 然后尝试向mailB.com 投递 ,也是通过SMTP, 如果发送失败, 就给userA 发一个投递失败的消息。
4. mailB.com 接收到以后, 存到userB的邮箱里, userB 就可以通过POP3 协议进行收取了
这里唯一做的变化就是让邮件服务器可以暂存邮件, 转发邮件。
于是他们发布了QuickMail 的第2版, 大受欢迎, 很快全世界的邮件服务器都连起来了。
小王和老周由于设计和实现了电子邮件的系统, 在IT界声名鹊起。
5
创业
时间过得很快,90年代初, 有个叫做蒂姆·伯纳斯·李的家伙发明了WWW 互联网, 之前大家只是通过主机相连, 通过telnet , email, bbs 等交流信息, 没想到html ,http以及浏览器出现以后,互联网能够如此的多彩多姿。
小王( 不, 这时候已经是老王了)看到了其中的商机: 既然大家都习惯用浏览器上网, 为什么不把Quickmail 也搬到互联网上去呢?
我可以开发一个基于Web 的邮件系统, 任何想要的人都可以分配一个免费的电子邮件账户 ! 并且在浏览器中使用 !
老王去找老板, 可是老板一直觉得之前的Quickmail 卖的这么好,是公司的主要现金流来源, 搞个免费的Web系统, 那不是革了自己的命吗? 所以一直不支持。
老王感慨于老板的短视, 于是联合老周出来创业了, 有了之前的系统做基础, 他们很快搞出了一套叫做coolmail 的web系统, 在推广上, 他们创造性的采用了一种叫做“病毒营销”的策略:
系统刚开始的时候不接受公开注册申请,而是通过自己的员工等首批成功注册的用户对外发出测试邀请。
即每个用户拥有若干个coolmail账号发放的权限,以邀请的形式发给若干个朋友,幸运者加入后各自也将拥有几个邀请资格,发放给更多的朋友。
试想想,全球每天有多少人接收了coolmail邀请,又有多少人在将他的邀请当作礼物一样发放出去,不需要自己费时费力做推广,业务就像病毒曼延一样由用户自动传播开去,每个参与者都在帮自己宣传。
当然coolmail本身产品质量也是非常过硬的。
coolmail 用户群迅速的爆炸式的增长, 到了1998年, 已经有了几亿的用户, 这引起了想进入互联网的大鳄 microhard 公司的注意, 经过若干轮的谈判, 老王和老周把coolmail 以5亿美金卖了出去, 两人摇身一变成了亿万富豪, 从此就退休了。
后记
2001年, 我在中科院计算所做本科的毕业实习, 做的就是一个基于Web的Email 系统, 虽然很简陋, 但真的学到很多的东西, 尤其是第一次觉得这些协议和系统没什么神秘的,自己也能实现一套出来,那种成就感是无与伦比的。
回想起那时候啃RFC英文协议的痛苦, 以及调试SMTP,POP3客户端程序时的挣扎, 真是感慨万千。
特以此文作为纪念。
扩展阅读:
公众号:码农翻身
“码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。