【问题标题】:DRY Layouts For Grails Emails?Grails 电子邮件的 DRY 布局?
【发布时间】:2016-06-11 21:32:43
【问题描述】:

我正在尝试清理我的 grails 项目中的一些电子邮件视图。我的团队对每封电子邮件都使用相同的介绍、徽标和签名。我试图将它们放入传统的 grails 布局文件中并使用元标记 <meta name="layout" content="email"/> 调用它,但它似乎不起作用。有没有另一种方法可以为这些电子邮件模板创建一个单一的布局?

【问题讨论】:

  • 这行不通。您需要查看与电子邮件模板中的图像 cid 标签匹配的内联图像附件。多个图像 = 多个内联附件

标签: email grails layout


【解决方案1】:

我试图弄清楚你所说的 DRY 是什么意思,我认为它一定是一些红宝石术语,我猜你的意思是模板。

HTML 电子邮件的问题实际上是跨所有语言的标准问题,例如在包含徽标(页眉/页脚)时。标准各不相同,虽然它可能适用于某些邮件客户端,但可能不适用于例如 web 邮件,即 gmail 等。

诀窍是使用内联图像,我会给你一些示例:

所以这是一个示例控制器 - 这是我自己的代码,但来自不同的部分。这是给你一个想法,或者我应该说不是很好地解释了关于多内联图像的具体说明:

class Mycontroller() { 
   pivate final static String TEMPLATE='/emails/emailTemplate'
   def emailService
   def doEmail() { 
    def images=[]
    //Where this list contains a map of photo Ids(could be macde up, the photo content type and actual photo file Names (to go and grab from uploaded folder)
    images <<[id: "uImage${photo.id}", contentType: "${photo.contentType}", file: photo.file]
    images <<[id: "uImage${photo1.id}", contentType: "${photo1.contentType}", file: photo1.file]
    emailService.sendEmail(user.email, subject, TEMPLATE, [instance: bean, domainName:domainName, fqdn:fqdn ], images)
  }
}

我有一个列表,如果上面的图片包含照片 ID、内容类型和实际文件名(以文本形式)发送到 emailService.sendEmail

private void sendEmail(email,mysubject,template,templateModel,List images) throws Exception {
        List<String> recipients = []       
        try {
            mailService.sendMail {
                //this must be set true and at the top for inline images to work
                multipart true
                if (recipients) {
                    to recipients
                }
                else {
                    to email
                }
                if (config.admin.emailFrom) {
                    if (Environment.current == Environment.DEVELOPMENT && config.admin.emailFromDev ) {
                        from "${config.admin.emailFromDev}"
                    } else {
                        from "${config.admin.emailFrom}"
                    }
                }
                subject mysubject
                //actual content must be html sent to fill in a grails template
                html Holders.grailsApplication.mainContext.groovyPageRenderer.render(template: template, model: templateModel)
                //Main Site logo
                inline 'inlineImage', 'image/png', new File("/opt/site-stuff/myLogo.png")
                //Additional images 
                if (images) {
                    images?.each { a ->
                        inline "${a.id}", "${a.contentType}", new File("${a.file}")
                    }
                }
            }
        }
        catch (e) {
            //throw new Exception(e.message)
            log.error "Problem sending email ${e.message}"
        }
    }

现在,您认为可以像在布局中那样使用 grails 模板的部分不是您想要的,如上所示,您可以看到它正在呈现模板,但模板是典型的 gsp 模板而是一个完整的 html 页面:


/电子邮件/电子邮件模板

<%@ page contentType="text/html;charset=UTF-8" %>
<!doctype html>
<html>
<head>
<style>
    .site-icon img {
        width: 300px;
        margin-top:-50px;
    }
    .site-logo img {
        min-width: 25em;
        max-width: 45em;
    }
    .menu {
        background: #CCC;
    }
    a {
        text-decoration: none;
    }
    .menu a {
        color : #FF0000;
        text-decoration: none;
        font-weight:bold;
    }
    .menu a:hover {
        color : #00FFFF;
        background: #ccc;
    }    
</style>
</head>
<body style=" background-color: blue; font-size: 1.0em;">
<table  width="100%" border="0" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF">
    <tr style="background: red;"><td colspan="3" class="site-logo">
        <img src="cid:inlineImage"/>
        <h1 style="display:inline; margin-top:-2em;"><g:message code="domain.label"/></h1>
    </td>
    </tr>

      <g:each in="${instance.results}" var="user" status="ii">
      <tr><td>
       <div class="image">
                    <g:if test="${user.profilePhoto}">
                        <img src="cid:uImage${user.id}"/>
                    </g:if>
                </div>

           </td></tr>

      </g:each>
</table>

您看到 html 电子邮件的主要问题是 CSS 样式不能很好地工作,它在某些情况下可以工作,但在很多情况下,您最好还是坚持使用传统表格并使用样式标签来正确声明您的布局.

忘记使用您的实际站点 CSS 文件,因为就此过程而言,这是直接生成和发送的电子邮件。它不知道您的网站 CSS 文件。

关于我们正在谈论的多个图像

这里是用户列表

usera {usera 照片} / userA 描述 userb {userb 照片} / userB 描述

上述解决方案将拥有您添加执行此操作所需的所有内联图像所需的一切。这意味着您要在电子邮件中附加图像,因此如果图像很大,那么您也要附加它们,因此诀窍是重新格式化图像/调整它们的大小。

对于您自己的网站徽标,您可以直接执行此操作,并拥有一个单独的文件/文件夹,其中包含要通过电子邮件发送的实际大小,但对于动态调整大小,您可以尝试以下操作:

   static Map getPhoto(Photos photo, int width=100,int height=100) {
        File f
        def contentType
        if (photo.status==Photos.ACTIVE) {
            def id = photo.id
            def imageSHa = photo.imageSHa
            contentType = photo.contentType
            def fileExtension = photo.fileExtension
            //remove . from fileExtension
            def noDotExtension = fileExtension.substring(1)
            def user = photo.user
            f = new File(ROOT_PATH + '/' + user.username + '/' + imageSHa);
            if (f.exists() && !f.isDirectory()) {
                f = new File(ROOT_PATH + '/' + user.username + '/' + imageSHa+'_email');
                if (!f.exists()) {
                    def imageStream = new FileInputStream(ROOT_PATH + '/' + user.username + '/' + imageSHa)
                    def image = FileCopyUtils.copyToByteArray(imageStream).encodeBase64().toString()
                    def caption = photo.caption
                    def position = photo.position
                    // String caption=photo.caption
                    //Lets present the image as a thumbNail
                    imageStream = new FileInputStream(ROOT_PATH + '/' + user.username + '/' + imageSHa)
                    def imageBuffer = ImageIO.read(imageStream)
                    def scaledImg = Scalr.resize(imageBuffer, Scalr.Method.QUALITY, width, height, Scalr.OP_ANTIALIAS)
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    ImageIO.write(scaledImg, noDotExtension, os)
                    InputStream is = new ByteArrayInputStream(os.toByteArray())

                    def scaledImage = FileCopyUtils.copyToByteArray(is).encodeBase64().toString()
                    //imageSHa = DigestUtils.shaHex(scaledImg)
                    byte[] data = Base64.decodeBase64(scaledImage)
                    OutputStream stream = new FileOutputStream(ROOT_PATH + '/' + user.username + '/' + imageSHa+'_email')
                    stream.write(data)
                    f = new File(ROOT_PATH + '/' + user.username + '/' + imageSHa+'_email');
                }
                return [file:f, contentType:'img/'+fileExtension.substring(1)]
            }

        }
        return [:]
    }

这现在映射到我在上面进行图像映射时:

 def res = PhotosBean.getPhoto(ui.attributes.profilePhoto)
                            if (res) {
                                images << [id: "uImage${ui.id}", contentType: "${res.contentType}", file: res.file]
                            }

希望这能解决我为实现 html 电子邮件而必须经历的许多头痛问题,其中包含所需数量的图像并全部调整为我想要的大小

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2014-11-14
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 2021-04-13
  • 1970-01-01
  • 2014-04-16
  • 1970-01-01
相关资源
最近更新 更多