1<?php 2 3declare(strict_types=1); 4 5/** 6 * @copyright 2017, Morris Jobke <hey@morrisjobke.de> 7 * @copyright 2017, Lukas Reschke <lukas@statuscode.ch> 8 * 9 * @author Bjoern Schiessle <bjoern@schiessle.org> 10 * @author brad2014 <brad2014@users.noreply.github.com> 11 * @author Joas Schilling <coding@schilljs.com> 12 * @author Julius Härtl <jus@bitgrid.net> 13 * @author Lukas Reschke <lukas@statuscode.ch> 14 * @author Morris Jobke <hey@morrisjobke.de> 15 * @author Roeland Jago Douma <roeland@famdouma.nl> 16 * @author Tomasz Paluszkiewicz <tomasz.paluszkiewicz@gmail.com> 17 * 18 * @license GNU AGPL version 3 or any later version 19 * 20 * This program is free software: you can redistribute it and/or modify 21 * it under the terms of the GNU Affero General Public License as 22 * published by the Free Software Foundation, either version 3 of the 23 * License, or (at your option) any later version. 24 * 25 * This program is distributed in the hope that it will be useful, 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * GNU Affero General Public License for more details. 29 * 30 * You should have received a copy of the GNU Affero General Public License 31 * along with this program. If not, see <http://www.gnu.org/licenses/>. 32 * 33 */ 34 35namespace OCA\Appointments\Email; 36 37use OCP\Defaults; 38use OCP\IL10N; 39use OCP\IURLGenerator; 40use OCP\Mail\IEMailTemplate; 41 42/** 43 * Class EMailTemplate 44 * 45 * addBodyText and addBodyButtonGroup automatically opens the body 46 * addFooter, renderHtml, renderText automatically closes the body and the HTML if opened 47 * 48 */ 49class EMailTemplateNC implements IEMailTemplate { 50 /** @var Defaults */ 51 protected $themingDefaults; 52 /** @var IURLGenerator */ 53 protected $urlGenerator; 54 /** @var IL10N */ 55 protected $l10n; 56 /** @var string */ 57 protected $emailId; 58 /** @var array */ 59 protected $data; 60 61 /** @var string */ 62 protected $subject = ''; 63 /** @var string */ 64 protected $htmlBody = ''; 65 /** @var string */ 66 protected $plainBody = ''; 67 /** @var bool indicated if the footer is added */ 68 protected $headerAdded = false; 69 /** @var bool indicated if the body is already opened */ 70 protected $bodyOpened = false; 71 /** @var bool indicated if there is a list open in the body */ 72 protected $bodyListOpened = false; 73 /** @var bool indicated if the footer is added */ 74 protected $footerAdded = false; 75 76 protected $head = <<<EOF 77<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 78<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" style="-webkit-font-smoothing:antialiased;background:#f3f3f3!important"> 79<head> 80 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 81 <meta name="viewport" content="width=device-width"> 82 <title></title> 83 <style type="text/css">@media only screen{html{min-height:100%;background:#F5F5F5}}@media only screen and (max-width:610px){table.body img{width:auto;height:auto}table.body center{min-width:0!important}table.body .container{width:95%!important}table.body .columns{height:auto!important;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:30px!important;padding-right:30px!important}th.small-12{display:inline-block!important;width:100%!important}table.menu{width:100%!important}table.menu td,table.menu th{width:auto!important;display:inline-block!important}table.menu.vertical td,table.menu.vertical th{display:block!important}table.menu[align=center]{width:auto!important}}</style> 84</head> 85<body style="-moz-box-sizing:border-box;-ms-text-size-adjust:100%;-webkit-box-sizing:border-box;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;Margin:0;background:#f3f3f3!important;box-sizing:border-box;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;min-width:100%;padding:0;text-align:left;width:100%!important"> 86 <span class="preheader" style="color:#F5F5F5;display:none!important;font-size:1px;line-height:1px;max-height:0;max-width:0;mso-hide:all!important;opacity:0;overflow:hidden;visibility:hidden"> 87 </span> 88 <table class="body" style="-webkit-font-smoothing:antialiased;Margin:0;background:#f3f3f3!important;border-collapse:collapse;border-spacing:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;height:100%;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;width:100%"> 89 <tr style="padding:0;text-align:left;vertical-align:top"> 90 <td class="center" align="center" valign="top" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 91 <center data-parsed="" style="min-width:580px;width:100%"> 92EOF; 93 94 protected $tail = <<<EOF 95 </center> 96 </td> 97 </tr> 98 </table> 99 <!-- prevent Gmail on iOS font size manipulation --> 100 <div style="display:none;white-space:nowrap;font:15px courier;line-height:0"> </div> 101 </body> 102</html> 103EOF; 104 105 protected $header = <<<EOF 106<table align="center" class="wrapper header float-center" style="Margin:0 auto;background:#8a8a8a;background-color:%s;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%"> 107 <tr style="padding:0;text-align:left;vertical-align:top"> 108 <td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:20px;text-align:left;vertical-align:top;word-wrap:break-word"> 109 <table align="center" class="container" style="Margin:0 auto;background:0 0;border-collapse:collapse;border-spacing:0;margin:0 auto;padding:0;text-align:inherit;vertical-align:top;width:580px"> 110 <tbody> 111 <tr style="padding:0;text-align:left;vertical-align:top"> 112 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 113 <table class="row collapse" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%"> 114 <tbody> 115 <tr style="padding:0;text-align:left;vertical-align:top"> 116 <center data-parsed="" style="min-width:580px;width:100%%"> 117 <img class="logo float-center" src="%s" alt="%s" align="center" style="-ms-interpolation-mode:bicubic;Margin:0 auto;clear:both;display:block;float:none;margin:0 auto;outline:0;text-align:center;text-decoration:none" height="50"> 118 </center> 119 </tr> 120 </tbody> 121 </table> 122 </td> 123 </tr> 124 </tbody> 125 </table> 126 </td> 127 </tr> 128</table> 129<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%"> 130 <tbody> 131 <tr style="padding:0;text-align:left;vertical-align:top"> 132 <td height="80px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:80px;font-weight:400;hyphens:auto;line-height:80px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> </td> 133 </tr> 134 </tbody> 135</table> 136EOF; 137 138 protected $heading = <<<EOF 139<table align="center" class="container main-heading float-center" style="Margin:0 auto;background:0 0!important;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:580px"> 140 <tbody> 141 <tr style="padding:0;text-align:left;vertical-align:top"> 142 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 143 <h1 class="text-center" style="Margin:0;Margin-bottom:10px;color:inherit;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:24px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:center;word-wrap:normal">%s</h1> 144 </td> 145 </tr> 146 </tbody> 147</table> 148<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%"> 149 <tbody> 150 <tr style="padding:0;text-align:left;vertical-align:top"> 151 <td height="40px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:40px;font-weight:400;hyphens:auto;line-height:40px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> </td> 152 </tr> 153 </tbody> 154</table> 155EOF; 156 157 protected $bodyBegin = <<<EOF 158<table align="center" class="wrapper content float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%"> 159 <tr style="padding:0;text-align:left;vertical-align:top"> 160 <td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 161 <table align="center" class="container has-shadow" style="Margin:0 auto;background:#fefefe;border-collapse:collapse;border-spacing:0;box-shadow:0 1px 2px 0 rgba(0,0,0,.2),0 1px 3px 0 rgba(0,0,0,.1);margin:0 auto;padding:0;text-align:inherit;vertical-align:top;width:580px"> 162 <tbody> 163 <tr style="padding:0;text-align:left;vertical-align:top"> 164 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 165 <table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%"> 166 <tbody> 167 <tr style="padding:0;text-align:left;vertical-align:top"> 168 <td height="60px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:60px;font-weight:400;hyphens:auto;line-height:60px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> </td> 169 </tr> 170 </tbody> 171 </table> 172EOF; 173 174 protected $bodyText = <<<EOF 175<table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%"> 176 <tbody> 177 <tr style="padding:0;text-align:left;vertical-align:top"> 178 <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px"> 179 <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 180 <tr style="padding:0;text-align:left;vertical-align:top"> 181 <th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left"> 182 <p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:left">%s</p> 183 </th> 184 <th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th> 185 </tr> 186 </table> 187 </th> 188 </tr> 189 </tbody> 190</table> 191EOF; 192 193 // note: listBegin (like bodyBegin) is not processed through sprintf, so "%" is not escaped as "%%". (bug #12151) 194 protected $listBegin = <<<EOF 195<table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%"> 196 <tbody> 197 <tr style="padding:0;text-align:left;vertical-align:top"> 198 <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px"> 199 <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%"> 200EOF; 201 202 protected $listItem = <<<EOF 203 <tr style="padding:0;text-align:left;vertical-align:top"> 204 <td style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left;width:15px;"> 205 <p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;padding-left:10px;text-align:left">%s</p> 206 </td> 207 <td style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left"> 208 <p class="text-left" style="Margin:0;Margin-bottom:10px;color:#555;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;padding-left:10px;text-align:left">%s</p> 209 </td> 210 <td class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></td> 211 </tr> 212EOF; 213 214 protected $listEnd = <<<EOF 215 </table> 216 </th> 217 </tr> 218 </tbody> 219</table> 220EOF; 221 222 protected $buttonGroup = <<<EOF 223<table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 224 <tbody> 225 <tr style="padding:0;text-align:left;vertical-align:top"> 226 <td height="50px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:50px;font-weight:400;hyphens:auto;line-height:50px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> </td> 227 </tr> 228 </tbody> 229</table> 230<table align="center" class="row btn-group" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%"> 231 <tbody> 232 <tr style="padding:0;text-align:left;vertical-align:top"> 233 <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px"> 234 <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 235 <tr style="padding:0;text-align:left;vertical-align:top"> 236 <th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left"> 237 <center data-parsed="" style="min-width:490px;width:100%%"> 238 <table class="button btn default primary float-center" style="Margin:0 0 30px 0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0 0 30px 0;margin-right:15px;max-height:40px;max-width:200px;padding:0;text-align:center;vertical-align:top;width:auto;background:%1\$s;background-color:%1\$s;color:#fefefe;"> 239 <tr style="padding:0;text-align:left;vertical-align:top"> 240 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 241 <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 242 <tr style="padding:0;text-align:left;vertical-align:top"> 243 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:0 solid %2\$s;border-collapse:collapse!important;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 244 <a href="%3\$s" style="Margin:0;border:0 solid %4\$s;border-radius:2px;color:%5\$s;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;outline:1px solid %6\$s;text-decoration:none">%7\$s</a> 245 </td> 246 </tr> 247 </table> 248 </td> 249 </tr> 250 </table> 251 <table class="button btn default secondary float-center" style="Margin:0 0 30px 0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0 0 30px 0;max-height:40px;max-width:200px;padding:0;text-align:center;vertical-align:top;width:auto"> 252 <tr style="padding:0;text-align:left;vertical-align:top"> 253 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 254 <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 255 <tr style="padding:0;text-align:left;vertical-align:top"> 256 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;background:#777;border:0 solid #777;border-collapse:collapse!important;color:#fefefe;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 257 <a href="%8\$s" style="Margin:0;background-color:#fff;border:0 solid #777;border-radius:2px;color:#6C6C6C!important;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;outline:1px solid #CBCBCB;padding:10px 25px 10px 25px;text-align:left;text-decoration:none">%9\$s</a> 258 </td> 259 </tr> 260 </table> 261 </td> 262 </tr> 263 </table> 264 </center> 265 </th> 266 <th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th> 267 </tr> 268 </table> 269 </th> 270 </tr> 271 </tbody> 272</table> 273EOF; 274 275 protected $button = <<<EOF 276<table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 277 <tbody> 278 <tr style="padding:0;text-align:left;vertical-align:top"> 279 <td height="50px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:50px;font-weight:400;hyphens:auto;line-height:50px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> </td> 280 </tr> 281 </tbody> 282</table> 283<table align="center" class="row btn-group" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%"> 284 <tbody> 285 <tr style="padding:0;text-align:left;vertical-align:top"> 286 <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px"> 287 <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 288 <tr style="padding:0;text-align:left;vertical-align:top"> 289 <th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left"> 290 <center data-parsed="" style="min-width:490px;width:100%%"> 291 <table class="button btn default primary float-center" style="Margin:0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0;max-height:40px;padding:0;text-align:center;vertical-align:top;width:auto;background:%1\$s;color:#fefefe;background-color:%1\$s;"> 292 <tr style="padding:0;text-align:left;vertical-align:top"> 293 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 294 <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%"> 295 <tr style="padding:0;text-align:left;vertical-align:top"> 296 <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:0 solid %2\$;border-collapse:collapse!important;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 297 <a href="%3\$s" style="Margin:0;border:0 solid %4\$s;border-radius:2px;color:%5\$s;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;outline:1px solid %5\$s;text-decoration:none">%7\$s</a> 298 </td> 299 </tr> 300 </table> 301 </td> 302 </tr> 303 </table> 304 </center> 305 </th> 306 <th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th> 307 </tr> 308 </table> 309 </th> 310 </tr> 311 </tbody> 312</table> 313EOF; 314 315 protected $bodyEnd = <<<EOF 316 317 </td> 318 </tr> 319 </tbody> 320 </table> 321 </td> 322 </tr> 323</table> 324EOF; 325 326 protected $footer = <<<EOF 327<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%"> 328 <tbody> 329 <tr style="padding:0;text-align:left;vertical-align:top"> 330 <td height="60px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:60px;font-weight:400;hyphens:auto;line-height:60px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> </td> 331 </tr> 332 </tbody> 333</table> 334<table align="center" class="wrapper footer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%"> 335 <tr style="padding:0;text-align:left;vertical-align:top"> 336 <td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> 337 <center data-parsed="" style="min-width:580px;width:100%%"> 338 <table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%"> 339 <tbody> 340 <tr style="padding:0;text-align:left;vertical-align:top"> 341 <td height="15px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:15px;font-weight:400;hyphens:auto;line-height:15px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word"> </td> 342 </tr> 343 </tbody> 344 </table> 345 <p class="text-center float-center" align="center" style="Margin:0;Margin-bottom:10px;color:#C8C8C8;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:12px;font-weight:400;line-height:16px;margin:0;margin-bottom:10px;padding:0;text-align:center">%s</p> 346 </center> 347 </td> 348 </tr> 349</table> 350EOF; 351 352 /** 353 * @param Defaults $themingDefaults 354 * @param IURLGenerator $urlGenerator 355 * @param IL10N $l10n 356 * @param string $emailId 357 * @param array $data 358 */ 359 public function __construct(Defaults $themingDefaults, 360 IURLGenerator $urlGenerator, 361 IL10N $l10n, 362 $emailId, 363 array $data) { 364 $this->themingDefaults = $themingDefaults; 365 $this->urlGenerator = $urlGenerator; 366 $this->l10n = $l10n; 367 $this->htmlBody .= $this->head; 368 $this->emailId = $emailId; 369 $this->data = $data; 370 } 371 372 /** 373 * Sets the subject of the email 374 * 375 * @param string $subject 376 */ 377 public function setSubject(string $subject) { 378 $this->subject = $subject; 379 } 380 381 /** 382 * Adds a header to the email 383 */ 384 public function addHeader() { 385 if ($this->headerAdded) { 386 return; 387 } 388 $this->headerAdded = true; 389 390 $logoUrl = $this->urlGenerator->getAbsoluteURL($this->themingDefaults->getLogo(false)); 391 $this->htmlBody .= vsprintf($this->header, [$this->themingDefaults->getColorPrimary(), $logoUrl, $this->themingDefaults->getName()]); 392 } 393 394 /** 395 * Adds a heading to the email 396 * 397 * @param string $title 398 * @param string|bool $plainTitle Title that is used in the plain text email 399 * if empty the $title is used, if false none will be used 400 */ 401 public function addHeading(string $title, $plainTitle = '') { 402 if ($this->footerAdded) { 403 return; 404 } 405 if ($plainTitle === '') { 406 $plainTitle = $title; 407 } 408 409 $this->htmlBody .= vsprintf($this->heading, [htmlspecialchars($title)]); 410 if ($plainTitle !== false) { 411 $this->plainBody .= $plainTitle . PHP_EOL . PHP_EOL; 412 } 413 } 414 415 /** 416 * Open the HTML body when it is not already 417 */ 418 protected function ensureBodyIsOpened() { 419 if ($this->bodyOpened) { 420 return; 421 } 422 423 $this->htmlBody .= $this->bodyBegin; 424 $this->bodyOpened = true; 425 } 426 427 /** 428 * Adds a paragraph to the body of the email 429 * 430 * @param string $text Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email 431 * @param string|bool $plainText Text that is used in the plain text email 432 * if empty the $text is used, if false none will be used 433 */ 434 public function addBodyText(string $text, $plainText = '') { 435 if ($this->footerAdded) { 436 return; 437 } 438 if ($plainText === '') { 439 $plainText = $text; 440 $text = htmlspecialchars($text); 441 } 442 443 $this->ensureBodyListClosed(); 444 $this->ensureBodyIsOpened(); 445 446 $this->htmlBody .= vsprintf($this->bodyText, [$text]); 447 if ($plainText !== false) { 448 $this->plainBody .= $plainText . PHP_EOL . PHP_EOL; 449 } 450 } 451 452 /** 453 * Adds a list item to the body of the email 454 * 455 * @param string $text Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email 456 * @param string $metaInfo Note: When $plainMetaInfo falls back to this, HTML is automatically escaped in the HTML email 457 * @param string $icon Absolute path, must be 16*16 pixels 458 * @param string|bool $plainText Text that is used in the plain text email 459 * if empty the $text is used, if false none will be used 460 * @param string|bool $plainMetaInfo Meta info that is used in the plain text email 461 * if empty the $metaInfo is used, if false none will be used 462 * @since 12.0.0 463 */ 464 public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '') { 465 $this->ensureBodyListOpened(); 466 467 if ($plainText === '') { 468 $plainText = $text; 469 $text = htmlspecialchars($text); 470 } 471 if ($plainMetaInfo === '') { 472 $plainMetaInfo = $metaInfo; 473 $metaInfo = htmlspecialchars($metaInfo); 474 } 475 476 $htmlText = $text; 477 if ($metaInfo) { 478 $htmlText = '<em style="color:#777;">' . $metaInfo . '</em><br>' . $htmlText; 479 } 480 if ($icon !== '') { 481 $icon = '<img src="' . htmlspecialchars($icon) . '" alt="•">'; 482 } else { 483 $icon = '•'; 484 } 485 $this->htmlBody .= vsprintf($this->listItem, [$icon, $htmlText]); 486 if ($plainText !== false) { 487 $this->plainBody .= ' * ' . $plainText; 488 if ($plainMetaInfo !== false) { 489 $this->plainBody .= ' (' . $plainMetaInfo . ')'; 490 } 491 $this->plainBody .= PHP_EOL; 492 } 493 } 494 495 protected function ensureBodyListOpened() { 496 if ($this->bodyListOpened) { 497 return; 498 } 499 500 $this->ensureBodyIsOpened(); 501 $this->bodyListOpened = true; 502 $this->htmlBody .= $this->listBegin; 503 } 504 505 protected function ensureBodyListClosed() { 506 if (!$this->bodyListOpened) { 507 return; 508 } 509 510 $this->bodyListOpened = false; 511 $this->htmlBody .= $this->listEnd; 512 } 513 514 /** 515 * Adds a button group of two buttons to the body of the email 516 * 517 * @param string $textLeft Text of left button; Note: When $plainTextLeft falls back to this, HTML is automatically escaped in the HTML email 518 * @param string $urlLeft URL of left button 519 * @param string $textRight Text of right button; Note: When $plainTextRight falls back to this, HTML is automatically escaped in the HTML email 520 * @param string $urlRight URL of right button 521 * @param string $plainTextLeft Text of left button that is used in the plain text version - if unset the $textLeft is used 522 * @param string $plainTextRight Text of right button that is used in the plain text version - if unset the $textRight is used 523 */ 524 public function addBodyButtonGroup(string $textLeft, 525 string $urlLeft, 526 string $textRight, 527 string $urlRight, 528 string $plainTextLeft = '', 529 string $plainTextRight = '') { 530 if ($this->footerAdded) { 531 return; 532 } 533 if ($plainTextLeft === '') { 534 $plainTextLeft = $textLeft; 535 $textLeft = htmlspecialchars($textLeft); 536 } 537 538 if ($plainTextRight === '') { 539 $plainTextRight = $textRight; 540 $textRight = htmlspecialchars($textRight); 541 } 542 543 $this->ensureBodyIsOpened(); 544 $this->ensureBodyListClosed(); 545 546 $color = $this->themingDefaults->getColorPrimary(); 547 $textColor = $this->themingDefaults->getTextColorPrimary(); 548 549 $this->htmlBody .= vsprintf($this->buttonGroup, [$color, $color, $urlLeft, $color, $textColor, $textColor, $textLeft, $urlRight, $textRight]); 550 $this->plainBody .= $plainTextLeft . ': ' . $urlLeft . PHP_EOL; 551 $this->plainBody .= $plainTextRight . ': ' . $urlRight . PHP_EOL . PHP_EOL; 552 553 } 554 555 /** 556 * Adds a button to the body of the email 557 * 558 * @param string $text Text of button; Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email 559 * @param string $url URL of button 560 * @param string $plainText Text of button in plain text version 561 * if empty the $text is used, if false none will be used 562 * 563 * @since 12.0.0 564 */ 565 public function addBodyButton(string $text, string $url, $plainText = '') { 566 if ($this->footerAdded) { 567 return; 568 } 569 570 $this->ensureBodyIsOpened(); 571 $this->ensureBodyListClosed(); 572 573 if ($plainText === '') { 574 $plainText = $text; 575 $text = htmlspecialchars($text); 576 } 577 578 $color = $this->themingDefaults->getColorPrimary(); 579 $textColor = $this->themingDefaults->getTextColorPrimary(); 580 $this->htmlBody .= vsprintf($this->button, [$color, $color, $url, $color, $textColor, $textColor, $text]); 581 582 if ($plainText !== false) { 583 $this->plainBody .= $plainText . ': '; 584 } 585 586 $this->plainBody .= $url . PHP_EOL; 587 588 } 589 590 /** 591 * Close the HTML body when it is open 592 */ 593 protected function ensureBodyIsClosed() { 594 if (!$this->bodyOpened) { 595 return; 596 } 597 598 $this->ensureBodyListClosed(); 599 600 $this->htmlBody .= $this->bodyEnd; 601 $this->bodyOpened = false; 602 } 603 604 /** 605 * Adds a logo and a text to the footer. <br> in the text will be replaced by new lines in the plain text email 606 * 607 * @param string $text If the text is empty the default "Name - Slogan<br>This is an automatically sent email" will be used 608 * @param string|null $lang 609 */ 610 public function addFooter(string $text = '',?string $lang = null) { 611 if($text === '') { 612 $text = $this->themingDefaults->getName() . ' - ' . $this->themingDefaults->getSlogan() . '<br>' . $this->l10n->t('This is an automatically sent email, please do not reply.'); 613 } 614 615 if ($this->footerAdded) { 616 return; 617 } 618 $this->footerAdded = true; 619 620 $this->ensureBodyIsClosed(); 621 622 $this->htmlBody .= vsprintf($this->footer, [$text]); 623 $this->htmlBody .= $this->tail; 624 $this->plainBody .= PHP_EOL . '-- ' . PHP_EOL; 625 $this->plainBody .= str_replace('<br>', PHP_EOL, $text); 626 } 627 628 /** 629 * Returns the rendered email subject as string 630 * 631 * @return string 632 */ 633 public function renderSubject(): string { 634 return $this->subject; 635 } 636 637 /** 638 * Returns the rendered HTML email as string 639 * 640 * @return string 641 */ 642 public function renderHtml(): string { 643 if (!$this->footerAdded) { 644 $this->footerAdded = true; 645 $this->ensureBodyIsClosed(); 646 $this->htmlBody .= $this->tail; 647 } 648 return $this->htmlBody; 649 } 650 651 /** 652 * Returns the rendered plain text email as string 653 * 654 * @return string 655 */ 656 public function renderText(): string { 657 if (!$this->footerAdded) { 658 $this->footerAdded = true; 659 $this->ensureBodyIsClosed(); 660 $this->htmlBody .= $this->tail; 661 } 662 return $this->plainBody; 663 } 664} 665