Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.
When developing an email template, you often face issues such as:
-
setting the same (often prehistoric) attributes and css properties across the whole project like:
<table width="600" cellpadding="0" cellspacing="0" border="0"> <tr> <td width="600" valign="top"> <img src="image.jpg" width="400" height="300" alt="Image" border="0" style="display: block">
-
using
font
tag unconveniently -
setting
img
sizes manually -
having multiple language versions (or other small differences between templates) for one layout
-
using same values across whole project (widths etc.) - that could be accessed as variables (and in some cases could also take a default configuration value when not set, like font parameters)
Produced code is often hard to maintain.
The framework brings configured Smarty plugins and CLI interface, so you can develop project like this:
{$marginHeight = 50}
{table}
{tr}
{td colspan=2}
{font size=20}Title{/font}
{/td}
{/tr}
{margin height=$marginHeight colspan=2}
{tr}
{td width=400}
{a href="http://example.com/"}{img src="image.jpg"}{/a}
{/td}
{td width=200 align=left padding="0 0 0 10px"}
{font bold=true}{#configVariable#}{/font}
{/td}
{/tr}
{/table}
<p>
Of course, you can use your own markup or easily create custom Smarty plugins, like {literal}{h1}Header{/h1}{/literal}.
</p>
And run the watcher:
iemail compile [project_name] -w
The code is converted (may vary according to the actual settings) to:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"> #outlook a {padding:0;} body{width:100% !important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;} #backgroundTable {margin:0; padding:0; width:100% !important; line-height: 100% !important;} table td {border-collapse: collapse;} </style>
</head>
<body>
<table cellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;">
<tr>
<td width="600" colspan="2" valign="top" align="center">
<font color="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font>
</td>
</tr>
<tr>
<td height="50" colspan="2" style="font-size:1px;"> </td>
</tr>
<tr>
<td width="400" valign="top" align="center">
<a href="http://example.com/" style="text-decoration:none;text-decoration:none !important;">
<img src="image.jpg" width="400" height="200" alt="Click Show Images option to see the picture" vspace="0" hspace="0" border="0" style="display:block;margin:0;border:none;outline:none;text-decoration:none;-ms-interpolation-mode:bicubic;" />
</a>
</td>
<td width="200" valign="top" align="left" style="padding:0 0 0 10px;">
<b>
<font color="#000000" size="3" face="Arial,Tahoma,sans-serif" style="font-size:13px;">This content is set in the configuration file</font>
</b>
</td>
</tr>
</table>
<p>
Of course, you can use your own markup or easily create custom Smarty plugins, like {h1}Header{/h1}.
</p>
</body>
</html>
To use the framework you need the following software:
- PHP >= 5.5 with openssl and mbstring extensions enabled
- Composer
- for Windows, use the installer
- for Linux, install globally
- optionally, if you want to benefit from gulp, i.e. live browser reload on each change with Browsersync, you will need to install: nodejs and of course gulp (the new proper way, by gulp-cli)
-
Windows
- unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into
c:\PHP
- add
c:\PHP
to your PATH environment variable - rename
c:\PHP\php.ini-development
tophp.ini
, edit and uncomment:
extension_dir = "ext"
extension=php_mbstring.dll
extension=php_openssl.dll
- unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into
-
Linux - run in the terminal:
sudo apt-get install php5-cli
- Open a console/terminal window.
- Run:
composer global require implico/email-framework
- Add the Composer's global bin folder to your PATH variable. First, to get the path, run:
composer global config bin-dir --absolute
And then:
- Windows: follow the instructions
- Linux: edit the
/etc/environment
file (or/etc/profile
if you don't see the PATH definition there) as a root user and restart system
- You can now start a new project - see the examples section to find out more.
composer global update implico/email-framework
The global executable is named iemail
. Run it from your projects dir (e.g. email-projects
).
iemail create projects_dir_name
Creates a new projects directory (where your projects will be kept) with specified project_name
. Creates _custom
subdirectory, with master config file and custom plugins dir.
Options:
projects_dir_name
: directory name
Example:
iemail create email-projects
iemail init project_name [base_project_name]
Creates a new project with specified project_name
. Run it in the directory created with create
command.
Contents of the base_project_name
are copied into a new directory. First, the script searches for it in the current working directory, then in the core framework samples
.
Options:
base_project_name
: enter the name of the base project to copy; defaults toplain
Example (creates test
project based on the multilang
core example):
iemail init test multilang
iemail compile project_name [-s script_name(s)] [-d projects_dir] [-w] [-o m|f]
Compiles project with specified project_name
. Options:
-s
(--script
): script name(s), if not set - all scripts are compiled-d
(--dir
): projects directory, defaults to current direcotry-w
(--watch
): watch mode - starts watching your project dir and compiles on any change-o
(--output
): output mode - minified (m) or formatted with indentation (f)
Example (compiles and then watches test
project for changes):
iemail compile test -w
iemail send project_name [-s script_name] [-d projects_dir] [-t address(es)] [-f filename] [--fromname name] [--fromaddress address] [-u subject] [-a attachment(s)] [--minified] [-i interval_ms] [--errorstop]
Sends test email(s) for the specified project_name
. All images are converted and embedded as cids. SMTP and default options are set in the configuration file.
Options:
-s
(--script
): script name, defaults toindex
-d
(--dir
): projects directory, defaults toprojects
-t
(--toaddress
): target address(es), defaults to configuration settings (for multiple, use:-t a1@a.com -t a2@a.com
)-f
(--toaddressfn
): name of a text file in the project's root directory with target addresses (separated by newline)--fromname
: from name, defaults to configuration settings--fromaddress
: from address, defaults to configuration settings-u
(--subject
): email subject, defaults to configuration settings-a
(--attachments
): attaches one or more files from the output directory (for multiple, use:-a file1 -a file2
)-m
(--minified
): uses minified script version instead of formatted-l
(--log
): logs addresses into the project's root directory:log-done.txt
: addresses to which sending succeededlog-fail.txt
: addresses to which sending eventually failed
-i
(--interval
): interval in ms between sending each email, defaults to 1000--errorstop
: quits on error
Example (sends test
project to test@example.com):
iemail send test -t test@example.com
The newly initialized project directory comes with package.json
and gulpfile.js
, allowing you to use the gulp watch and Browsersync live browser reload on each source code change. Technically, the watcher just executes the compiler in a normal way and then refreshes the browser.
For the first run, after using iemail create
, enter the new project directory and execute (assuming nodejs and gulp are already installed):
npm install
Then you can use a simple gulp api:
gulp -p project_name [-s script_name] [-a] [-r]
Compiles a project and opens a web browser. Then watches the project, compiling and reloading the browser on changes.
Options:
-p
(--project
): project name (required)-s
(--script
): script name, defaults toindex
; if not specified (gulp -p sample -s
), all scripts are listed in the browser-a
(--params
): additional parameters passed to the compile command, e.g.gulp -p sample -a ' -om'
will produce the minified version (note the leading space)-r
(--resume
): prevents new browser window to be opened
The framework directory structure overview:
core
: PHP files, Smarty plugins and master config filesamples
: example projects, used also for bootstrapingvendor
: modules installed with Composer
The _custom
subdirectory contains optional: custom master config file and your own Smarty plugins - place them in the plugins
directory.
Other dirs contain per project files. Each of them has the following structure:
configs
: configuration for the whole project and for particular scriptsviews
: view templates:layout.tpl
: the main view (layout) filescripts
: if you want to have multiple views for one main layout (which differ in language or some details like colors, graphics), place them here; by default, there is only one script:script.tpl
; see the Multilang example for use case
styles
: CSS styles (as Smarty templates, so you can e.g. access config variables)layout.tpl
: main styles included in your view layout template (you can rename or create new ones)inline.tpl
: styles to put inline with CssToInlineStyles (you cannot rename it, but can include other templates from within)
outputs
: compiled project files (HTML); put your images here
Reference scheme:
{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}
Where:
parameter1
is set to0
parameter2
is set to configuration valueconfig_value
parameter3
is not displayed
Attribute names which are equal to the HTML ones are not camelCase (like cellpadding
, bordercolor
), others like lineHeight
are.
Standard parameters are:
style
: additional CSS style, likeborder: 1px solid #000;
id
: id attributeclass
: one or more classes separated by spaceattrs
: additional HTML attributes, likevalign="middle" border="0"
These won't be described in the reference below.
Function plugin has only the start tag, e.g. {margin height=20}
, other (block) must have the ending tag, e.g. {table}...{/table}
.
Specify width, height, font sizes without units.
{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=false border=0 bordercolor=false align=#tableAlign# maxWidth=false style=false id=false class=false attrs=false}
Notes:
maxWidth
: sets themax-width
style and creates an Outlook-conditional wrapper table
{tr style=false id=false class=false attrs=false}
{td width=#tdWidth# height=false colspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=false background=false backgroundNoRepeat=true lineHeight=#tdLineHeight# borderRadius=false noFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=false id=false class=false attrs=false}
Notes:
- when using
background
(image), you will probably want to set a fallback color withbgcolor
; note that background images embedded as cids seem not to work with Gmail mobile app (but do work when referencing external URLs) backgroundNoRepeat
causes the background image to fill all the cell spacepadding
: set as a CSSpadding
property value, e.g.10px 20px
noFont
: blocks applying font styles even iffontStyleTdTag
config value is set totrue
overflow
: set totrue
forhidden
(shorthand)
Creates a row with specified height.
{margin height=false colspan=1 bgcolor=false style=false id=false class=false attrs=false}
{font color=#fontColor# size=#fontSize# sizeForce=false family=#fontFamily# bold=false italic=false underlined=false centered=false noWrap=false style=false id=false class=false attrs=false}
Notes:
sizeForce
: adds!important
to CSSfont-size
property value (useful when you don't want the font to be resized on e.g. mobile Gmail apps)bold
,italic
,underlined
,centered
: have aliases derived from the first letter; set any truthy value, like{font b=1}
noWrap
adds styles and replaces content white spaces with
{a href="" target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=false style=false id=false class=false attrs=false}
Notes:
textDecoration
: use CSS values fortext-decoration
propertybuttonHeight
: if you want to "buttonize" the link, set its height; you should addsizeForce=true
parameter to the{font}
used inside this button to prevent font scaling on mobile Gmail apps; you would also probably need to set the button background color on wrapping{td}
; see Button plugin for a cross-client solution
{button href="" width=false height=false bgcolor=false bordercolor=false borderRadius=false centered=true style=false id=false class=false attrs=false}
Notes:
- creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
centered
: refers to centering of the button content, remember to setalign="center"
for containing{td}
- you can nest markup to obtain font styles, e.g.
{button href="http://example.com/" width=150 height=40 bgcolor="#e10000" borderRadius=10}
{font size=14 color="#ffffff" bold=1}See more{/font}
{/button}
{img src="" width=false height=false autoSize=#imgAutoSize# alt=#imgAlt# padding=false margin=0 marginV=0 marginH=0 align=false display=#imgDisplay# border=0 bordercolor=false style=false id=false class=false attrs=false}
Notes:
autoSize
: if true, when width and height is not specified, actual image dimensions are takenmarginV
andmarginH
: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)
To force white space strip (in the formatted version), use the following syntax:
#(strip)[stripped_code]#(/strip)
Default settings are defined in the master file core/config.conf
. To change them, edit (if they do not exist - create) the following files:
[projects_dir]/_custom/config.conf
: your custom common config applied to all projects[projects_dir]/[project_name]/configs/config.conf
: config applied to the project[projects_dir]/[project_name]/configs/scripts/[script_name].conf
: per script config (name it as the script name)
All most recent options are described in the master file. You can change (among others):
- encoding, font defining mode (as a
font
tag,span
and/or in atd
cell tag) - default table and cells attributes, font family/color/size, link and img styles
- sending test email options, such as default subject/target address or SMTP access
To create a directory where you will keep your projects, use the create
command:
iemail create email-projects
This will create a directory named email-projects
with custom config and plugins folder.
Then, go to this directory and run the init
command:
iemail init my_project_name
By default, the base (copy source) project is the plain
sample from the core (unless you create own plain
project, then it will be the default for bootstraping). You can specify base project by the second parameter:
iemail init my_project_name other_project_name
If the base project is not found in the current directory, it will be searched in the framework core sample
directory.
After initialization, run compiler in watch mode:
iemail compile my_project_name -w
Open the script HTML file located in your project outputs
directory. Refresh on every compilation to see the changes.
Alternatively, use the more convenient gulp integration guide to watch for changes.
This is a plain, bootstrap project. Includes only a layout with the main table defined.
This shows how to build more complex projects, including lists and buttons.
Presents the way to build a responsive (in fact - fluid) project. Notes:
- config options
tableWidth
andtdWidth
are set to 100% - layout template:
<meta name="viewport">
is uncommented, primarily for Apple devices that support media queries (see the last media query that limits table width)- added Outlook max-width hack as a conditional comment (before and after the main table definition)
- added max-width to the main table (for e.g. Gmail)
- all width units (tables, cells, images) are set in percentage
Multi-language project presents two ways of defining language-specific content for English and Polish. The concept is that the layout template (layout.tpl
) is extended by language scripts (see Smarty template inheritance), in this case en.tpl
and pl.tpl
.
First way is to set script-specific config values in the configs/scripts
directory, and then just use it like {#title#}
.
Second way is to inject content by using blocks in language scripts.
To use the framework in your own PHP scripts:
-
install it with Composer
{ "require": { "implico/email-framework": "1.*" }, }
-
to render an email, first create a Smarty object:
$smarty = new \Smarty();
-
add plugins dir
$smarty->addPluginsDir(path_to_core_plugins_dir);
Replace
path_to_core_plugins_dir
with the actual path, e.g.__DIR__.'/vendor/email-framework/core/plugins/'
. -
load config file(s)
$smarty->configLoad(path_to_config_file1); //first one should be the core config, e.g. __DIR__.'/vendor/email-framework/core/config.conf' $smarty->configLoad(path_to_config_file2); //project or script-specific config files
-
set directories the templates are referring to, like this:
$smarty->setTemplateDir(array( 0 => path_to_project, 'layouts' => path_to_project_layouts, 'scripts' => path_to_project_scripts, 'styles' => path_to_project_css ));
-
execute the script and then send it using your favorite library (like PHPMailer or Swift Mailer)
$html = $smarty->fetch(path_to_script) //send the email //...
-
for PHPMailer, you can embed images as cids using the msgHTML method
-
to create a vertical line (
<hr>
), you can use the following code:{margin height=1 bgcolor="#000000"}
-
to create an unordered list, use
•
entity, e.g.:{tr} {td align=center} {font}•{/font} {/td} {td} {font}list item 1{/font} {/td} {/tr}
-
if you have repeated code, take advantage of functions; if the code repeats among projects, you can think about creating own plugins (template functions or block functions)
-
set line heights in pixels, rather than percentages or numbers (Outlook will treat it as pixels); if a Gmail mobile app wrongly converts it on small screens, target such more modern clients in the CSS by a media query and apply a patch, e.g.
@media all { #footer { line-height: 1.4; } }
-
to achieve precision (and avoid Outlook bugs in certain cases), define cell paddings by nesting tables, instead of setting CSS
padding
property -
set a background color on tables, rather than on cells (causes gap lines on iPhones)
[x] integration with gulp for:
- more optimized watch
- auto-refresh by Browsersync
[ ] use of TinyPNG
[ ] error handling when one of required project subdirectories does not exist
Take a look at other interesting tools and frameworks: