我们将要构建什么
在本教程中我将向你展示我是如何构建我的免费模板Crowder的。下面是它的最终效果图。
这套模板的特性:
- 邮件响应式
- 网络字体
- 在表格单元格内的背景图
注意:每个人的编写电子邮件的工作流程都是不同的,你可能更喜欢以其他方式编码或者工作这完全ok。
准备设计稿
在你打开代码编辑器前,应该准备好你的邮件设计稿。我喜欢按照Photoshop指南绘制要分割设计的位置(见下图)。这有两个目的,首先我可以看到我要在哪里以及如何对图片进行切片,其次我可以大致在思想上准备好接下来的编码工作,不断思考并勾勒表格的整体结构。
准备HTML骨架
我保存了一个骨架,这是构建电子邮件前的基础。我喜欢从头开始编写来保持代码的干净和整洁。如果你还没有一个HTML的骨架我建议你可以先保存我的,稍后我们将对这个骨架做一个拆分。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;">
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE" />
<title>Page title</title>
<style type="text/css">
@media screen and (max-width: 630px) {
}
</style>
</head>
<body style="padding:0; margin:0">
<table border="0" cellpadding="0" cellspacing="0" style="margin: 0; padding: 0" width="100%">
<tr>
<td align="center" valign="top">
</td>
</tr>
</table>
</body>
</html>
这里是我们为文件设置的DOCTYPE,我见过许多关于关于如何设置的讨论,我认为只要它没有不起作用就用它吧,这里我们无需深究。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
接下来,设置内容类型和视口大小。下面的meta标记formate-detection是格式检测有助于确保禁止把数字转化为拨号链接,IE=EDGE将确保永远以最新的IE版本模式来显示网页。
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;">
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE" />
我们将CSS放置到骨架中,稍后会对此再做添加
<style type="text/css">
@media screen and (max-width: 630px) {
}
</style>
最后是内容的表格
<body style="padding:0; margin:0">
<table border="0" cellpadding="0" cellspacing="0" style="margin: 0; padding: 0" width="100%">
<tr>
<td align="center" valign="top">
</td>
</tr>
</table>
</body>
head区域的编写
这是一个枯燥的步骤但也是必须的,在这个区域我们将会增加一些重要的东西。
首先,我将添加我的客户端修复程序。这里没有太多内容需要介绍,它们修复了不同电子邮件客户端之间的一些小错误和怪癖。我们将这些添加到头部的<style>
</style>标记内。
/* Some resets and issue fixes */
#outlook a { padding:0; }
body{ width:100% !important; -webkit-text; size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0; }
.ReadMsgBody { width: 100%; }
.ExternalClass {width:100%;}
.backgroundTable {margin:0 auto; padding:0; width:100%;!important;}
table td {border-collapse: collapse;}
.ExternalClass * {line-height: 115%;}
/* End reset */
接下来,因为这封邮件使用的是网络字体,我们需要导入这些
@import url(http://fonts.googleapis.com/css?family=Roboto:300); /*Calling our web font*/
要注意添加的注释,这对代码的阅读和管理非常重要。
Web字体有着不错的支持,但是我们应该为那些不会选择它的客户选择具有类似功能的后备字体。所以我将字体从Roboto后退到Arial。
最后,为了邮件的响应式我添加了永远不会改变的媒体查询,并在所有电子邮件中使用。
首先这就是我们在移动设备上强制表单元格堆叠的方式。
/* Display block allows us to stack elements */
*[class="mobile-column"] {display: block;}
这是用来堆放的。
/* Some more stacking elements */
*[class="mob-column"] {float: none !important;width: 100% !important;}
这一点可以允许我们在移动端隐藏些东西。
/* Hide stuff */
*[class="hide"] {display:none !important;}
这使我们能够达到100%的宽。
/* This sets elements to 100% width and fixes the height issues too, a god send */
*[class="100p"] {width:100% !important; height:auto !important;}
这适用于列堆叠但是需要下方有间隔。
/* For the 2x2 stack */
*[class="condensed"] {padding-bottom:40px !important; display: block;}
这使得内容在移动设备上居中对齐,对于保持阅读模式非常重要。
/* Centers content on mobile */
*[class="center"] {text-align:center !important; width:100% !important; height:auto !important;}
这使我们可以达到100%的宽,周围是padding填充。
/* 100percent width section with 20px padding */
*[class="100pad"] {width:100% !important; padding:20px;}
同上,但只是在左侧和右侧做一个填充。
/* 100percent width section with 20px padding left & right */
*[class="100padleftright"] {width:100% !important; padding:0 20px 0 20px;}
同上,只在上方和下方做填充。
/* 100percent width section with 20px padding top & bottom */
*[class="100padtopbottom"] {width:100% !important; padding:20px 0px 20px 0px;}
head区域总结
我们已经添加了许多东西,下面是我们在style标签内应该看到的样子。
<style>
@import url(http://fonts.googleapis.com/css?family=Roboto:300); /*Calling our web font*/
/* Some resets and issue fixes */
#outlook a { padding:0; }
body{ width:100% !important; -webkit-text; size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0; }
.ReadMsgBody { width: 100%; }
.ExternalClass {width:100%;}
.backgroundTable {margin:0 auto; padding:0; width:100%;!important;}
table td {border-collapse: collapse;}
.ExternalClass * {line-height: 115%;}
/* End reset */
/* These are our tablet/medium screen media queries */
@media screen and (max-width: 630px){
/* Display block allows us to stack elements */
*[class="mobile-column"] {display: block;}
/* Some more stacking elements */
*[class="mob-column"] {float: none !important;width: 100% !important;}
/* Hide stuff */
*[class="hide"] {display:none !important;}
/* This sets elements to 100% width and fixes the height issues too, a god send */
*[class="100p"] {width:100% !important; height:auto !important;}
/* For the 2x2 stack */
*[class="condensed"] {padding-bottom:40px !important; display: block;}
/* Centers content on mobile */
*[class="center"] {text-align:center !important; width:100% !important; height:auto !important;}
/* 100percent width section with 20px padding */
*[class="100pad"] {width:100% !important; padding:20px;}
/* 100percent width section with 20px padding left & right */
*[class="100padleftright"] {width:100% !important; padding:0 20px 0 20px;}
/* 100percent width section with 20px padding top & bottom */
*[class="100padtopbottom"] {width:100% !important; padding:20px 0px 20px 0px;}
}
</style>
构建hero section
我们将从hero section开始一路向下写:
下面我将介绍所有代码,并将它们逐一分解。这并不会像听起来那样可怕。
<table width="640" cellspacing="0" cellpadding="0" bgcolor="#" class="100p">
<tr>
<td background="images/header-bg.jpg" bgcolor="#3b464e" width="640" valign="top" class="100p">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:640px;">
<v:fill type="tile" src="images/header-bg.jpg" color="#3b464e" />
<v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
<![endif]-->
<div>
<table width="640" border="0" cellspacing="0" cellpadding="20" class="100p">
<tr>
<td valign="top">
<table border="0" cellspacing="0" cellpadding="0" width="600" class="100p">
<tr>
<td align="left" width="50%" class="100p"><img src="images/logo.png" alt="Logo" border="0" style="display:block" /></td>
<td width="50%" class="hide" align="right" style="font-size:16px; color:#FFFFFF;"><font face="'Roboto', Arial, sans-serif"><a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a></font></td>
</tr>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="600" class="100p">
<tr>
<td height="35"></td>
</tr>
<tr>
<td align="center" style="color:#FFFFFF; font-size:24px;">
<font face="'Roboto', Arial, sans-serif">
<span style="font-size:44px;">Introducing Crowder</span><br />
<br />
<Span style="font-size:24px;">Your ultimate crowd<br />
sourcing solution</Span>
<br /><br />
<table border="0" cellspacing="0" cellpadding="10" style="border:2px solid #FFFFFF;">
<tr>
<td align="center" style="color:#FFFFFF; font-size:16px;"><font face="'Roboto', Arial, sans-serif"><a href="##" style="color:#FFFFFF; text-decoration:none;">FIND OUT MORE</a></font></td>
</tr>
</table>
</font>
</td>
</tr>
<tr>
<td height="35"></td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->
</td>
</tr>
</table>
让我们开始吧,这是表的开头:
<table width="640" cellspacing="0" cellpadding="0" bgcolor="#" class="100p">
<tr>
<td background="images/header-bg.jpg" bgcolor="#3b464e" width="640" valign="top" class="100p">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:640px;">
<v:fill type="tile" src="images/header-bg.jpg" color="#3b464e" />
<v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
<![endif]-->
<div>
第一行很简单,一张640像素宽的表格。它有一个100p的class类名,正如我们前面所提到的,我们在更小的屏幕上强制它100%的宽度:
<table width="640" cellspacing="0" cellpadding="0" bgcolor="#" class="100p">
<tr>
接下来的一点比较棘手,我们需要背景图像。众所周知,作为Outlook是不支持背景图像的。但是,不要害怕! VML hack就在这里!color是在背景图不生效的时候做的样式回退,会显示一个#3b464的背景色
<td background="images/header-bg.jpg" bgcolor="#3b464e" width="640" valign="top" class="100p">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:640px;">
<v:fill type="tile" src="images/header-bg.jpg" color="#3b464e" />
<v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
<![endif]-->
<div>
现在我们已经为hero创建了容器,接下来我们应该搞定内容部分,这是代码
<table width="640" border="0" cellspacing="0" cellpadding="20" class="100p">
<tr>
<td valign="top">
<table border="0" cellspacing="0" cellpadding="0" width="600" class="100p">
<tr>
<td align="left" width="50%" class="100p"><img src="images/logo.png" alt="Logo" border="0" style="display:block" /></td>
<td width="50%" class="hide" align="right" style="font-size:16px; color:#FFFFFF;"><font face="'Roboto', Arial, sans-serif"><a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a></font></td>
</tr>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="600" class="100p">
<tr>
<td height="35"></td>
</tr>
<tr>
<td align="center" style="color:#FFFFFF; font-size:24px;">
<font face="'Roboto', Arial, sans-serif">
<span style="font-size:44px;">Introducing Crowder</span><br />
<br />
<Span style="font-size:24px;">Your ultimate crowd<br />
sourcing solution</Span>
<br /><br />
<table border="0" cellspacing="0" cellpadding="10" style="border:2px solid #FFFFFF;">
<tr>
<td align="center" style="color:#FFFFFF; font-size:16px;"><font face="'Roboto', Arial, sans-serif"><a href="##" style="color:#FFFFFF; text-decoration:none;">FIND OUT MORE</a></font></td>
</tr>
</table>
</font>
</td>
</tr>
<tr>
<td height="35"></td>
</tr>
</table>
</td>
</tr>
</table>
首先是logo和nav部分:
<table border="0" cellspacing="0" cellpadding="0" width="600" class="100p">
<tr>
<td align="left" width="50%" class="100p"><img src="images/logo.png" alt="Logo" border="0" style="display:block" /></td>
<td width="50%" class="hide" align="right" style="font-size:16px; color:#FFFFFF;"><font face="'Roboto', Arial, sans-serif"><a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a></font></td>
</tr>
</table>
这是logo表单元,我们设置了50%的表单元宽在小屏幕上会是100%的宽。
<td align="left" width="50%" class="100p"><img src="images/logo.png" alt="Logo" border="0" style="display:block" /></td>
下面是导航。你可能会注意到其中包含了可怕的字体标签。这样Outlook将显示我们的web字体回退。我还把导航隐藏在手机上。
<td width="50%" class="hide" align="right" style="font-size:16px; color:#FFFFFF;"><font face="'Roboto', Arial, sans-serif"><a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a> | <a href="#" style="color:#FFFFFF; text-decoration:none;">HOME</a></font></td>
我们已经设置了徽标和导航。现在,让我们进入标题,副标题和按钮。 同样,这里是所有代码。我们再将其分解。
<table border="0" cellspacing="0" cellpadding="0" width="600" class="100p">
<tr>
<td height="35"></td>
</tr>
<tr>
<td align="center" style="color:#FFFFFF; font-size:24px;">
<font face="'Roboto', Arial, sans-serif">
<span style="font-size:44px;">Introducing Crowder</span><br />
<br />
<Span style="font-size:24px;">Your ultimate crowd<br />
sourcing solution</Span>
<br /><br />
<table border="0" cellspacing="0" cellpadding="10" style="border:2px solid #FFFFFF;">
<tr>
<td align="center" style="color:#FFFFFF; font-size:16px;"><font face="'Roboto', Arial, sans-serif"><a href="##" style="color:#FFFFFF; text-decoration:none;">FIND OUT MORE</a></font></td>
</tr>
</table>
</font>
</td>
</tr>
<tr>
<td height="35"></td>
</tr>
</table>
大多数情况下,间距非常重要,因此我们将重点关注这一部分:
<td align="center" style="color:#FFFFFF; font-size:24px;">
<font face="'Roboto', Arial, sans-serif">
<span style="font-size:44px;">Introducing Crowder</span><br />
<br />
<span style="font-size:24px;">Your ultimate crowd<br />
sourcing solution</span>
<br /><br />
<table border="0" cellspacing="0" cellpadding="10" style="border:2px solid #FFFFFF;">
<tr>
<td align="center" style="color:#FFFFFF; font-size:16px;"><font face="'Roboto', Arial, sans-serif"><a href="##" style="color:#FFFFFF; text-decoration:none;">FIND OUT MORE</a></font></td>
</tr>
</table>
</font>
</td>
你会注意到前面的<font face =“'Roboto',Arial,sans-serif”>有关早期Outlook回退的。 让我们来看看按钮:
<table border="0" cellspacing="0" cellpadding="10" style="border:2px solid #FFFFFF;">
<tr>
<td align="center" style="color:#FFFFFF; font-size:16px;"><font face="'Roboto', Arial, sans-serif"><a href="##" style="color:#FFFFFF; text-decoration:none;">FIND OUT MORE</a></font></td>
</tr>
</table>
我们在表格周围添加了一个边框,该边框围绕按钮,以赋予其一些样式。 cellpadding =“ 10”给我们在文本和边框之间留出一些空间。
表格里面,可怕的<font face =“'Roboto',Arial,sans-serif”>又回来了。不用担心这是必需的!
很好,我们刚刚完成了hero部分!让我们来看看移动端和桌面端效果的并排。
让我们继续吧...
建立icon区
现在我们将要创建这一部分
为了方便起见,我们使用蓝色条将图标网格分离。
让我们开始蓝色条:
<table width="640" border="0" cellspacing="0" cellpadding="20" bgcolor="#2a8e9d" class="100p">
<tr>
<td align="center" style="font-size:24px; color:#FFFFFF;"><font face="'Roboto', Arial, sans-serif">Why Crowder?</font></td>
</tr>
</table>
我们有一个640像素的表,在更小的屏幕上被强制变成100%。cellpadding=“20”为我们提供了一种简单的方法,可以在它的所有边上添加20个像素的填充,从而在设备之间保持一致。
表格嵌套着表格,这是全部的代码,现在我们来剖析它。
<table width="640" border="0" cellspacing="0" cellpadding="20" class="100p" bgcolor="#FFFFFF">
<tr>
<td align="center" valign="top">
<table border="0" cellpadding="0" cellspacing="0" class="100padtopbottom" width="600">
<tr>
<td align="left" class="condensed" valign="top">
<table align="left" border="0" cellpadding="0" cellspacing="0" class="mob-column" width="290">
<tr>
<td valign="top" align="center">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" align="center" class="100padleftright">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="135" align="center"><a href="#"><img src="images/icon-1.png" border="0" style="display:block;"/></a></td>
<td width="20"></td>
<td width="135" align="center"><a href="#"><img src="images/icon-1.png" border="0" style="display:block;"/></a></td>
</tr>
</table>
</td>
</tr>
<tr>
<td height="10"></td>
</tr>
<tr>
<td valign="top" class="100padleftright" align="center">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" width="135" align="center" style="font-size:16px; color:#2a8e9d;"><font face="'Roboto', Arial, sans-serif">Customise your user messages</font></td>
<td width="20"></td>
<td valign="top" width="135" align="center" style="font-size:16px; color:#2a8e9d;"><font face="'Roboto', Arial, sans-serif">100% unique privacy options</font></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td width="20" class="hide"></td>
<td align="left" class="condensed" valign="top">
<table align="left" border="0" cellpadding="0" cellspacing="0" class="mob-column" width="290">
<tr>
<td valign="top" align="center">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" align="center" class="100padleftright">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="135" align="center"><a href="#"><img src="images/icon-1.png" border="0" style="display:block;"/></a></td>
<td width="20"></td>
<td width="135" align="center"><a href="#"><img src="images/icon-1.png" border="0" style="display:block;"/></a></td>
</tr>
</table>
</td>
</tr>
<tr>
<td height="10"></td>
</tr>
<tr>
<td valign="top" class="100padleftright" align="center">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" width="135" align="center" style="font-size:16px; color:#2a8e9d;"><font face="'Roboto', Arial, sans-serif">Fully customise your settings</font></td>
<td width="20"></td>
<td valign="top" width="135" align="center" style="font-size:16px; color:#2a8e9d;"><font face="'Roboto', Arial, sans-serif">Upload your product photos</font></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
因为很多都是重复的代码,所以我们将把重点放在那些重要的地方。
让我们快速看看周围的表格:
<table width="640" border="0" cellspacing="0" cellpadding="20" class="100p" bgcolor="#FFFFFF">
<tr>
<td align="center" valign="top">
这是我们经典的640像素的表格,在较小屏幕上显示100%的宽。而且cellpadding给我们留下了一致的间距。 现在让我们看一下左列,该列由前两个图标组成。
<td align="left" class="condensed" valign="top">
<table align="left" border="0" cellpadding="0" cellspacing="0" class="mob-column" width="290">
<tr>
<td valign="top" align="center">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" align="center" class="100padleftright">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="135" align="center"><a href="#"><img src="images/icon-1.png" border="0" style="display:block;"/></a></td>
<td width="20"></td>
<td width="135" align="center"><a href="#"><img src="images/icon-1.png" border="0" style="display:block;"/></a></td>
</tr>
</table>
</td>
</tr>
<tr>
<td height="10"></td>
</tr>
<tr>
<td valign="top" class="100padleftright" align="center">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" width="135" align="center" style="font-size:16px; color:#2a8e9d;"><font face="'Roboto', Arial, sans-serif">Customise your user messages</font></td>
<td width="20"></td>
<td valign="top" width="135" align="center" style="font-size:16px; color:#2a8e9d;"><font face="'Roboto', Arial, sans-serif">100% unique privacy options</font></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
这是定义列宽,并强制使得它堆叠。
<td align="left" class="condensed" valign="top">
<table align="left" border="0" cellpadding="0" cellspacing="0" class="mob-column" width="290">
<tr>
这样做的方式是因为每个列都是135像素宽。如果我们把这些邮件放在一行而不是2x2,我们会无缘无故地增加电子邮件的长度。
再往下看代码,我们会看到,这迫使我们的内容在更小的设备上左右两边都有填充。
<td valign="top" align="center" class="100padleftright">
这就是本节真正要说的。我们简单地复制上面的内容来创建第二列,得到一个2x2网格。下面是它们并排比较的方式:
创建bottom部分
下一步我们将要创建bottom部分。在我们搞定上面的堆叠后这是件轻而易举的事情。这是我们现在将要构建的:
让我们逐步解决这个问题。
首先是白色文本块,令人惊讶的是,它很简单。下面我们将其分解:
<table width="640" border="0" cellspacing="0" cellpadding="20" bgcolor="#ffffff" class="100p">
<tr>
<td align="center" style="font-size:16px; color:#848484;"><font face="'Roboto', Arial, sans-serif"><span style="color:#2a8e9d; font-size:24px;">We will amaze you</span><br />
<br />
<span style="font-size:16px;">Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without revolutionary ROI.</span></font>
</td>
</tr>
</table>
这张表格有20的cellpadding和100p的class,你应该现在知道他的作用了。
<table width="640" border="0" cellspacing="0" cellpadding="20" bgcolor="#ffffff" class="100p">
最好的一点是不管我们添加了多少内容,我们都能很好的阅读和堆叠。
接下来是非常简单的图像。
<table width="640" border="0" cellspacing="0" cellpadding="0" bgcolor="#ffffff" class="100p">
<tr>
<td align="center"><img src="images/ipad.png" class="100p" border="0" style="display:block" /></td>
</tr>
</table>
这是一个640像素/100%的中心对齐表。不同的是我们需要在小屏幕上设置100%的宽度。这使得它是流动的。
现在是蓝绿色部分,这和白色的一样,只是颜色相反。
以上就是从头开始编写响应式电子邮件的全部过程了。
翻译自:
https://litmus.com/community/learning/24-how-to-code-a-responsive-email-from-scratch
我特么直呼牛皮@(呵呵)