邮件模板开发

项目需求:开发一个邮件模板,用于向海外客户邮箱推送各种消息,需要根据消息类型,展示不同的内容。比如:异常告警的时候呈现的是一种形式,注册及忘记密码又是另一种形式。除此之外,同一个模板还需要兼容移动端和PC端。UI大致如下:

因此,需要考虑众多因素来实现这个需求。首先是邮件模板,经查阅资料及实践,发现网页邮箱借助于浏览器强大的渲染能力还是很好兼容的,但是邮箱客户端由于安全性及渲染能力的制约,并不能很好的渲染html文件,编写兼容性良好的html邮件模板,需要使用15年前的网页制作方法。主要经验总结如下:

1.Doctype

兼容性最好的Doctype是XHTML 1.0,所以我们常用的HTML5文件头不能使用,需要换上以下这种文件头Doctype,使用这种Doctype就意味着不能使用HTML5的语言。

<!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" />
  <title>HTML Email编写指南</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
 </head>
</html>

2.布局

由于不能使用HTML5的语法,并且邮箱客户端对CSS的支持情况不尽相同,所以布局要使用古老的table布局,且必须使用table布局,就不要使用div p等标签了。首先在最外层放置一个大表格,用来设置背景。

<body style="margin: 0; padding: 0;">
 <table border="1" cellpadding="0" cellspacing="0" width="100%">
  <tr>
   <td> Hello! </td>
  </tr>
 </table>
</body>

3.图片

图片是唯一可以引用的外部资源,鉴于安全性考虑,外部资源比如样式表文件、字体文件、视频文件等一律不能引用。

<img border="0" style="display:block;outline:none;text-decoration:none,-ms-interpolation-mode:bicubic;border:none;">

因为在有些邮箱里,图片不是默认加载的,往往加载前需要用户的许可。那么高宽的指定可以使邮件在没有图片撑出样子前也能保持良好的大小结构,加上 alt 属性更可以明确告知图片的内容让用户选择是否下载它们。

如果因为项目需要(比如需要适配 Retina 高分屏),width 和 height 属性更是必不可少的,并且由于一些 outlook 版本的奇葩表现,width 和 height 属性一定不要加上单位!一定不要加上单位!一定不要加上单位!重要的事情说三遍。

因为加上单位会使一些版本的 OutLook 无法正确识别,导致图片显示使用实际的宽高而非我们设置的。

<img width="10px" height="10px" src="*.png" />

style 内容里面 background 可以设置 color,但是 image 会被过滤,就是说不能通过 CSS 来设置背景图片了。但是有一个很有意思的元素属性,也叫 background,里面可以定义一个图片路径,但是功能有限,比如无法定位背景图片等。

例如要给一个单元格加一个背景,必须这样写:

<td background="*.png">
    <!-- ... -->
</td>

Outlook 2007-2013 不支持图片的 margin 与 padding 样式,必要的时候可以尝试 hspace 和 vspace 属性:

<img vspace="10" hspace="10" src="*.png" />

4.文本相关

所有的CSS规则,都需要采用行内样式。因为放置在网页头部的样式,会被Gmail客户端过滤掉。而我们面向海外的主要客户群使用的正式Gmail邮箱。

在 HTML 邮件中,font-family 只支持系统字体,不支持自定义字体,也不支持 font 简写,color 尽可能也不要使用简写。对于加粗字体,可以使用b标签而不要使用font-weight,前文介绍过,能用html标签和属性解决的样式问题就不要使用CSS样式。

5.行高

在 OutLook 中会有个默认的行高最小值,特别是当设置 font-family 为微软雅黑时,默认的行高差不多为 Word 中的两倍行距,如果 line-height 设置的值小于默认的行高,无论你设置的是多少,则始终使用默认值,在很多情况下这是不能忍的,好在有个神奇的 mso-line-height-rule,使用行高时添加 mso-line-height-rule:exactly; 就能使行高始终等于我们所设置的值。

<td style="mso-line-height-rule: exactly; line-height: 36px;">
    <!-- ... -->
</td>

这只是微软的CSS属性,对其他客户端没影响。并且该属性只在这块元素上有效。

整体总结

1.页面宽度请设定在550到650px以内。

2.使用table表格来布局。

3.如果需要邮件居中显示,请在table里设定align="center"。

4、不要写<style>标签、不要写class,所有CSS都用style属性,什么元素需要什么样式就用style写内联的CSS。

5、不要使用外链的css样式定义文字和图片(外链的css样式在邮件里将不能被读取,所以发送出去的邮件因为没有链接到样式,将会使你的邮件内容样式丢失),正确的写法:<td style="font-family:arial;font-size:12px;color:black">文字</td>。

6、不使用flash、java、javascript、frames、iframe、activeX以及DHTML,如果页面中的图片一定要动态的,请将flash文件转换成gif动画使用,但在outlook2007里,gif将不能正常显示,因为outlook2007限制gif动画。

7、不要使用<table></table>以外的body、meta和html之类的标签,部分邮箱系统会把这些过滤掉。

8、背景图片代码写法如下:<table background="background.gif" cellspacing="0" cellpadding="0"></table>,但请注意,outlook对背景图片不识别。

9.font-family属性不能为空,否则会被QQ屏蔽为垃圾邮件。

10.若邮件模板内侧边或者上下有空白间距,不要用 padding,必须得用标准的 td 来设定空白间距,否则会导致各个邮箱解析不同。

11、在 yahoo 邮箱里定义 line-height 的注意事项:需在块级元素里定义 line-height。如果 td 里有 p 标签,则 line-height 也必须在 p 中定义。无论是 td 还是 p,如果有超链接,则都必须在 a 标签里定义 line-height。如果只是在 td 或者 p 里面定义 line-height 的话,那 yahoo 邮箱将无法识别 a 里面的行高。

12.少用float, margin,padding. 绝对定位不能用,清除浮动用<table style="clear:both"></table>

13.如果 td 和 td 之间有间隔,使用<td style="border-bottom:10px solid #fff"></td>,这样写的话 td 之间是不会有间隔的。使用<td style="margin-bottom: 10px"></td>也是不会有空格的。如果 td 之间有间隙,必须用<td></td><td height="10px">&nbsp;</td><td></td>来隔开。但是如果是 table,则<table style="border-top:10px solid #ffffff; border-bottom:20px solid #ffffff"></table>里面的内容会在上下有空行。

14.少用图片,邮箱不会过滤你的img标签,但是系统往往会默认不载入陌生来信的图片,如果用了很多图片的邮件,在片没有载入的情况下,丑陋无比甚至看不清内容,没耐心的用户直接就删除了。图片上务必加上alt。

outlook 规则

1.在<td>里设置 margin 是无效的,不论是 margin-left、margin-right、margin-top 或者 margin-boottom 都没有效果。

2.如果要使用<P>标签要考虑到<P>标签本身自带的上下行之间的行高。

yahoo规则

在table里设定align="center"无法居中, 需要内联style=“margin:0 auto,width:XX”

foxmail 规则

foxmail中所有p标签的Margin:0; 使用p标签时需要设置margin

邮件模板正好之后,接下来就是要解决根据不同的消息类型来展示不同的内容这个问题,目前我们采用的是thymeleaf模板引擎。主要用到的渲染语法如下:

1.获取变量值

<p th:text="'Hello!, ' + ${name} + '!'" >3333</p>
全部替换
<p th:text="${copyright}"2018 Closeli, Inc., All rights reserved </p>

可以看出获取变量值用$符号,对于javaBean的话使用变量名.属性名方式获取,这点和EL表达式一样.

另外$表达式只能写在th标签内部,不然不会生效,上面例子就是使用th:text标签的值替换p标签里面的值,至于p里面的原有的值只是为了给前端开发时做展示用的.这样的话很好的做到了前后端分离.

2.引入图片url地址

Thymeleaf对于URL的处理是通过语法@{…}来处理

<a th:href="@{http://blog.csdn.net/u012706811}">绝对路径</a>
<a th:href="@{/}">相对路径</a>
<a th:href="@{css/bootstrap.min.css}">Content路径,默认访问static下的css文件夹</a>
动态获取src地址
<img alt="" width="300" src="cid:inlineCid0"/>

3.字符串替换

很多时候可能我们只需要对一大段文字中的某一处地方进行替换,可以通过字符串拼接操作完成:

<span th:text="'Welcome to our application, ' + ${user.name} + '!'"> 

4.布尔值条件判断

通过布尔值条件判断渲染来切换不同的显示界面从而达到预期效果,同时还用到了解析对象的语法th:utext

<div class="push-content" th:if="${pushContent != null}">
    <td th:text="${pushContent.title}">异常运动异常</td>
</div>

html5操作支持

th:abbr          th:accept             th:accept-charset
th:accesskey             th:action             th:align
th:alt             th:archive             th:audio
th:autocomplete             th:axis             th:background
th:bgcolor             th:border             th:cellpadding
th:cellspacing             th:challenge             th:charset
th:cite             th:class             th:classid
th:codebase             th:codetype             th:cols
th:colspan             th:compact             th:content
th:contenteditable             th:contextmenu             th:data
th:datetime             th:dir             th:draggable
th:dropzone             th:enctype             th:for
th:form             th:formaction             th:formenctype
th:formmethod             th:formtarget             th:fragment
th:frame             th:frameborder             th:headers
th:height             th:high             th:href
th:hreflang             th:hspace             th:http-equiv
 
th:icon             th:id             th:inline
th:keytype             th:kind             th:label
th:lang             th:list             th:longdesc
th:low             th:manifest             th:marginheight
th:marginwidth             th:max             th:maxlength
th:media             th:method             th:min
th:name            th:onabort            th:onafterprint
th:onbeforeprint            th:onbeforeunload            th:onblur
th:oncanplay            th:oncanplaythrough            th:onchange
th:onclick            th:oncontextmenu            th:ondblclick
th:ondrag            th:ondragend            th:ondragenter
th:ondragleave            th:ondragover            th:ondragstart
th:ondrop            th:ondurationchange            th:onemptied
th:onended            th:onerror            th:onfocus
th:onformchange            th:onforminput            th:onhashchange
th:oninput            th:oninvalid            th:onkeydown
th:onkeypress            th:onkeyup            th:onload
th:onloadeddata            th:onloadedmetadata            th:onloadstart
th:onmessage            th:onmousedown            th:onmousemove
th:onmouseout            th:onmouseover            th:onmouseup
th:onmousewheel            th:onoffline            th:ononline
th:onpause            th:onplay            th:onplaying
th:onpopstate            th:onprogress            th:onratechange
th:onreadystatechange            th:onredo            th:onreset
th:onresize            th:onscroll            th:onseeked
th:onseeking            th:onselect            th:onshow
th:onstalled            th:onstorage            th:onsubmit
th:onsuspend            th:ontimeupdate            th:onundo
th:onunload            th:onvolumechange            th:onwaiting
th:optimum            th:pattern            th:placeholder
th:poster            th:preload            th:radiogroup
th:rel            th:rev            th:rows
th:rowspan            th:rules            th:sandbox
th:scheme            th:scope            th:scrolling
th:size            th:sizes            th:span
th:spellcheck            th:src            th:srclang
th:standby            th:start            th:step
th:style            th:summary            th:tabindex
th:target            th:title            th:type
th:usemap            th:value            th:valuetype
th:vspace            th:width            th:wrap
 
th:vspace            th:width            th:wrap
th:xmlbase            th:xmllang            th:xmlspace

 

posted @ 2018-06-14 20:13  keang  阅读(2693)  评论(0编辑  收藏  举报