Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

implico-email-framework

Smarty Template Engine email coding framework. A kind of preprocessor that facilitates daily work with email templates.

Concept & example

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:

    <tablewidth="600" cellpadding="0" cellspacing="0" border="0"><tr><tdwidth="600" valign="top"><imgsrc="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=$marginHeightcolspan=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><metahttp-equiv="Content-Type" content="text/html; charset=utf-8" /><styletype="text/css">#outlooka {padding:0;} body{width:100%!important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;} .ExternalClass {width:100%;} .ExternalClass, .ExternalClassp, .ExternalClassspan, .ExternalClassfont, .ExternalClasstd, .ExternalClassdiv {line-height:100%;} #backgroundTable {margin:0; padding:0; width:100%!important; line-height:100%!important;} tabletd {border-collapse: collapse;} </style></head><body><tablecellpadding="0" cellspacing="0" border="0" align="center" width="600" style="border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"><tr><tdwidth="600" colspan="2" valign="top" align="center"><fontcolor="#000000" size="5" face="Arial,Tahoma,sans-serif" style="font-size:20px;">Title</font></td></tr><tr><tdheight="50" colspan="2" style="font-size:1px;">&nbsp;</td></tr><tr><tdwidth="400" valign="top" align="center"><ahref="http://example.com/" style="text-decoration:none;text-decoration:none !important;"><imgsrc="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><tdwidth="200" valign="top" align="left" style="padding:0 0 0 10px;"><b><fontcolor="#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>

Installation

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)

PHP installation

  • Windows

    1. unpack the downloaded PHP archive (e.g. PHP 5.6.x Non Thread Safe Zip - rather that 7.x) into c:\PHP
    2. add c:\PHP to your PATH environment variable
    3. rename c:\PHP\php.ini-development to php.ini, edit and uncomment:
    • extension_dir = "ext"
    • extension=php_mbstring.dll
    • extension=php_openssl.dll
  • Linux - run in the terminal:

    sudo apt-get install php5-cli
    

Framework installation

  1. Open a console/terminal window.
  2. Run:
composer global require implico/email-framework
  1. 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
  1. You can now start a new project - see the examples section to find out more.

Framework update

composer global update implico/email-framework

CLI

The global executable is named iemail. Run it from your projects dir (e.g. email-projects).

Initialize projects directory

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

Initialize new project

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 to plain

Example (creates test project based on the multilang core example):

iemail init test multilang

Compile project

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

Send test email(s)

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 to index
  • -d (--dir): projects directory, defaults to projects
  • -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 succeeded
    • log-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

Gulp integration

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 to index; 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

Directory structure

Framework

The framework directory structure overview:

  • core: PHP files, Smarty plugins and master config file
  • samples: example projects, used also for bootstraping
  • vendor: modules installed with Composer

Projects dir

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 scripts
  • views: view templates:
    • layout.tpl: the main view (layout) file
    • scripts: 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

Plugin reference

Reference scheme:

{plugin_name parameter1=0 parameter2=#config_value# parameter3=false}

Where:

  • parameter1 is set to 0
  • parameter2 is set to configuration value config_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, like border: 1px solid #000;
  • id: id attribute
  • class: one or more classes separated by space
  • attrs: additional HTML attributes, like valign="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

{table width=#tableWidth# cellpadding=0 cellspacing=0 bgcolor=falseborder=0 bordercolor=falsealign=#tableAlign# maxWidth=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • maxWidth: sets the max-width style and creates an Outlook-conditional wrapper table

Tr

{tr style=falseid=falseclass=falseattrs=false}

Td

{td width=#tdWidth# height=falsecolspan=1 align=#tdAlign# valign=#tdValign# padding=0 overflow=#tdOverflow# bgcolor=falsebackground=falsebackgroundNoRepeat=truelineHeight=#tdLineHeight# borderRadius=falsenoFont=!#fontStyleTdTag# fontFamily=#fontFamily# fontSize=#fontSize# fontColor=#fontColor# style=falseid=falseclass=falseattrs=false}

Notes:

  • when using background (image), you will probably want to set a fallback color with bgcolor; 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 space
  • padding: set as a CSS padding property value, e.g. 10px 20px
  • noFont: blocks applying font styles even if fontStyleTdTag config value is set to true
  • overflow: set to true for hidden (shorthand)

Vertical margin (function)

Creates a row with specified height.

{margin height=falsecolspan=1 bgcolor=falsestyle=falseid=falseclass=falseattrs=false}

Font

{font color=#fontColor# size=#fontSize# sizeForce=falsefamily=#fontFamily# bold=falseitalic=falseunderlined=falsecentered=falsenoWrap=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • sizeForce: adds !important to CSS font-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 &nbsp;

Link

{a href=""target=#aTarget# textDecoration=#aTextDecoration# buttonHeight=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • textDecoration: use CSS values for text-decoration property
  • buttonHeight: if you want to "buttonize" the link, set its height; you should add sizeForce=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

{button href=""width=falseheight=falsebgcolor=falsebordercolor=falseborderRadius=falsecentered=truestyle=falseid=falseclass=falseattrs=false}

Notes:

  • creates a Microsoft Outlook-compatible button (based on Bulletproof email buttons)
  • centered: refers to centering of the button content, remember to set align="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}

Image (function)

{img src=""width=falseheight=falseautoSize=#imgAutoSize# alt=#imgAlt# padding=falsemargin=0 marginV=0 marginH=0 align=falsedisplay=#imgDisplay# border=0 bordercolor=falsestyle=falseid=falseclass=falseattrs=false}

Notes:

  • autoSize: if true, when width and height is not specified, actual image dimensions are taken
  • marginV and marginH: vertical and horizontal margin (setting vspace and hspace attributes + CSS margin)

Force strip

To force white space strip (in the formatted version), use the following syntax: #(strip)[stripped_code]#(/strip)


Configuration

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 a td 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

Examples

Starting a new project

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.

Plain

This is a plain, bootstrap project. Includes only a layout with the main table defined.

Grid

This shows how to build more complex projects, including lists and buttons.

Responsive

Presents the way to build a responsive (in fact - fluid) project. Notes:

  • config options tableWidth and tdWidth 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

Multilang

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.


Integration

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


Quick tips

  • to create a vertical line (<hr>), you can use the following code:

    {margin height=1 bgcolor="#000000"}
  • to create an unordered list, use &bull; entity, e.g.:

    {tr}{td align=center}{font}&bull;{/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)


TODO

[x] integration with gulp for:

[ ] use of TinyPNG

[ ] error handling when one of required project subdirectories does not exist


Alternatives

Take a look at other interesting tools and frameworks:

About

Email coding framework based on Smarty Template Engine.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages