Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9dffdfa
configuration for tests
hybernaut Dec 14, 2016
abb4d27
more test config cleanup
hybernaut Dec 14, 2016
86c4d29
basic grunt task implemented
hybernaut Dec 14, 2016
e8ae024
read template files from filesystem
hybernaut Dec 15, 2016
4057b64
remove debug
hybernaut Dec 15, 2016
d988011
TODO for validating htmlBody/htmlFile etc.
hybernaut Dec 15, 2016
aac24c8
pretty good support for creating a server
hybernaut Dec 15, 2016
0873473
make create server task idempotent
hybernaut Dec 16, 2016
bcef316
refactor postmark-servers task using more idiomatic grunt usage
hybernaut Dec 16, 2016
71ccf91
duplicate test requires only one additional iteration, not two
hybernaut Dec 16, 2016
d3331ca
collect serverToken from secrets.json
hybernaut Dec 23, 2016
a48658c
read template config from templates.json
hybernaut Dec 23, 2016
a650a90
clean up example template files
hybernaut Dec 23, 2016
d87365d
simplify configuration
hybernaut Dec 23, 2016
bb51efc
use more canonical htmlBody and textBody
hybernaut Dec 23, 2016
3967d29
read templates.json in the postmark-templates task
hybernaut Dec 23, 2016
82fb13c
checkpoint: making progress toward saving templateID output
hybernaut Jan 3, 2017
a0a6f6d
output template info (including IDs) in templates.json format
hybernaut Jan 4, 2017
8fb62e5
update existing templates if templateID is present
hybernaut Jan 4, 2017
a518367
if update fails with bad Id, then revert to create
hybernaut Jan 4, 2017
6131196
move postmark-servers task to separate PR
hybernaut Jan 4, 2017
ac17e37
remove references to postmark-servers (for another PR)
hybernaut Jan 4, 2017
f3a7f7e
one last comment
hybernaut Jan 4, 2017
4a0b60c
node.js style callback
hybernaut Jan 13, 2017
aa3194b
simplify configuration following suggestions from @derekrushforth
hybernaut Jan 13, 2017
90ec805
log "created" vs "updated"
hybernaut Jan 13, 2017
315fd19
sample Gruntfile reads templates.json or defaults to inline config
hybernaut Jan 13, 2017
19fc6c4
Add the ability for `mailmason` to generate and upload/update templates.
randytarampi Jul 8, 2017
253a587
Further decouple `grunt-postmark` from `mailmason`.
randytarampi Dec 11, 2017
ee632f2
Add `postmark-templates-parse` and `postmark-templates-from-file`.
randytarampi Jan 8, 2018
b7e7a42
Add some documentation around `postmark-templates`.
randytarampi Jan 8, 2018
2cfb716
Bump version to `0.0.8`.
randytarampi Jan 8, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
.idea
secrets.json
config.json
secrets.json
64 changes: 49 additions & 15 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,69 @@
* https://github.com/wildbit/grunt-postmark.git
*/

module.exports = function(grunt) {
module.exports = function (grunt) {
var secret = grunt.file.readJSON('secrets.json');
var config = grunt.file.readJSON('config.json');

grunt.initConfig({
secrets: grunt.file.readJSON('secrets.json'),
secret: secret,
config: config,

/* Postmark
------------------------------------------------- */
------------------------------------------------- */
postmark: {
options: {
serverToken: '<%= secrets.serverToken %>'
serverToken: "<%= secret.postmark.server_token %>"
},
email: {
from: '[email protected]',
to: '[email protected]',
subject: 'Yo',
src: ['test/email.html']
from: "<%= config.postmark.from %>",
to: "<%= config.postmark.to %>",
subject: "<%= config.postmark.subject %>",
src: ["test/email.html"]
},
bulk: {
from: '[email protected]',
to: '[email protected]',
subject: 'Hey',
src: ['test/*.html']
from: "<%= config.postmark.from %>",
to: "<%= config.postmark.to %>",
subject: "<%= config.postmark.subject %>",
src: ["test/*.html"]
}
}
},

"postmark-templates-upload": {
options: {
ephemeralUploadResultsProperty: "<%= config.templates && config.templates.ephemeralUploadResultsProperty %>"
},
test_email: {
name: "testing-postmark-templates-js1-" + new Date().valueOf(),
subject: "Testing grunt-postmark-templates",
htmlSrc: "test/email.html",
textSrc: "test/email.txt"
},
test_email_again: {
name: "testing-postmark-templates-js2-" + new Date().valueOf(),
subject: "Testing grunt-postmark-templates (again)",
htmlSrc: "test/email.html",
textSrc: "test/email.txt"
},
test_email_inline_body: {
name: "testing-postmark-templates-js3-" + new Date().valueOf(),
subject: "Testing grunt-postmark-templates (inline body)",
htmlBody: "<html><body><h1>Another email test</h1></body></html>",
textBody: "Hello from grunt-postmark-templates\n"
}
},

"postmark-templates-output": {
options: {
cleanOutput: "<%= config.templates && config.templates.cleanOutput %>",
outputFile: "<%= config.templates && config.templates.outputFile %>",
ephemeralUploadResultsProperty: "<%= config.templates && config.templates.ephemeralUploadResultsProperty %>"
},
}
});

grunt.loadTasks('tasks');
grunt.loadTasks("tasks");

grunt.registerTask('default', ['postmark']);
grunt.registerTask("default", ["postmark", "postmark-templates"]);

};
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ After the plugin is installed, it can be enabled in your Gruntfile:
grunt.loadNpmTasks('grunt-postmark');
```

You'll need to add a [`config.json`](https://github.com/wildbit/mailmason/wiki/Getting-Started#create-configjson-required) and a [`secrets.json`](https://github.com/wildbit/mailmason/wiki/Getting-Started#create-secretsjson-optional) per the `mailmason` configuration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several details in this wiki entry that aren't relevant to grunt-postmark so this might confuse people who aren't using MailMason.

We should replace this with setup instructions specific to grunt-postmark. I can create the wiki page and link it once we've merged this PR.


## Postmark task
_Run this task with the `grunt postmark` command._

Expand Down
16 changes: 16 additions & 0 deletions example_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 1. Copy this file to "config.json" for your own version that won't be
// tracked in source control.
//
// 2. Delete these comments from the configuration so Grunt doesn't get confused
{
"postmark": {
"from": "[email protected]",
"to": "[email protected]",
"subject": "Test Email"
},
"templates": {
"ephemeralUploadResultsProperty": "postmark-templates-upload-results",
"cleanOutput": true,
"outputFile": "templates.json"
}
}
9 changes: 9 additions & 0 deletions example_secrets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 1. Copy this file to "secrets.json" for your own version that won't be
// tracked in source control.
//
// 2. Delete these comments from the configuration so Grunt doesn't get confused
{
"postmark": {
"server_token": "YOUR_POSTMARK_SERVER_TOKEN_HERE"
}
}
3 changes: 0 additions & 3 deletions secrets_example.json

This file was deleted.

138 changes: 138 additions & 0 deletions tasks/grunt-postmark-templates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* grunt-postmark-templates
* push templates to a Postmark server for use with SendTemplatedEmail
*
* https://github.com/wildbit/grunt-postmark.git
*/

module.exports = function (grunt) {
var DEFAULT_EPHEMERAL_UPLOAD_RESULTS_PROPERTY = 'postmark-templates-upload-results';
var DEFAULT_OUTPUT_FILE_NAME = 'templates.json';
var DEFAULT_CLEAN_OUTPUT = false;

grunt.registerMultiTask('postmark-templates-upload', 'Create or update Postmark templates', function () {
var done = this.async();
var options = this.options({
ephemeralUploadResultsProperty: DEFAULT_EPHEMERAL_UPLOAD_RESULTS_PROPERTY
});
var ephemeralUploadResultsProperty = options.ephemeralUploadResultsProperty || DEFAULT_EPHEMERAL_UPLOAD_RESULTS_PROPERTY;
var template = this.data;

var serverToken = options.serverToken || grunt.config('secret.postmark.server_token');

if (!serverToken) {
grunt.fail.warn('Missing Postmark server token \n');
}

if (!template.name) {
grunt.fail.warn('Missing required template property "name" \n');
}

if (!template.subject) {
grunt.fail.warn('Missing required template property "subject" \n');
}

if (!template.htmlBody && !template.htmlSrc) {
grunt.log.error('Missing template property "htmlBody" or "htmlSrc"\n');
}

if (!template.textBody && !template.textSrc) {
grunt.log.error('Missing template property "textBody" or "textSrc"\n');
}

var postmark = require('postmark');
var client = new postmark.Client(serverToken);

// read the referenced files, but hold on to the original filenames
var expanded = {
Name: template.name,
Subject: template.subject,
HtmlBody: template.htmlBody || grunt.file.read(template.htmlSrc),
TextBody: template.textBody || grunt.file.read(template.textSrc),
TemplateId: template.templateId,
};

if (expanded.TemplateId) {
client.editTemplate(expanded.TemplateId, expanded, function (err, response) {
if (err && err.code === 1101) {
grunt.log.warn('Template ' + expanded.TemplateId + ' not found, so attempting create');
delete template.templateId;
delete expanded.TemplateId;
client.createTemplate(expanded.TemplateId, function (err, response) {
grunt.log.writeln('Template ' + expanded.Name + ' created: ' + JSON.stringify(response.TemplateId));
handleResponse(err, done, response, template, ephemeralUploadResultsProperty);
});
} else {
grunt.log.writeln('Template ' + expanded.Name + ' updated: ' + JSON.stringify(response.TemplateId));
handleResponse(err, done, response, template, ephemeralUploadResultsProperty);
}
});
} else {
client.createTemplate(expanded, function (err, response) {
grunt.log.writeln('Template ' + expanded.Name + ' created: ' + JSON.stringify(response.TemplateId));
handleResponse(err, done, response, template, ephemeralUploadResultsProperty);
});
}
});

function handleResponse(err, done, response, template, ephemeralUploadResultsProperty) {
if (err){
errorMessage(err);
done();
} else {
template.templateId = response.TemplateId;
// compile the templates for use by the `postmark-templates-output` task
var updatedTemplates = grunt.config.get(ephemeralUploadResultsProperty) || {};
updatedTemplates[template.name] = template;
grunt.config.set(ephemeralUploadResultsProperty, updatedTemplates);

done();
}
}

function errorMessage(err) {
if (err.message) {
grunt.log.warn('Error: ' + err.message);
} else {
grunt.log.warn('Error: ' + JSON.stringify(err));
}
}

// invoke this task after postmark-templates to get an output file containing the resulting template IDs
// this is in the same format as the postmark-templates config.

grunt.registerTask('postmark-templates-output', 'Write out the resulting template IDs', function () {
var options = this.options({
cleanOutput: DEFAULT_CLEAN_OUTPUT,
outputFile: DEFAULT_OUTPUT_FILE_NAME,
ephemeralUploadResultsProperty: DEFAULT_EPHEMERAL_UPLOAD_RESULTS_PROPERTY
});
var ephemeralUploadResultsProperty = options.ephemeralUploadResultsProperty || DEFAULT_EPHEMERAL_UPLOAD_RESULTS_PROPERTY;
var outputFile = options.outputFile || DEFAULT_OUTPUT_FILE_NAME;
var cleanOutput = options.cleanOutput || DEFAULT_CLEAN_OUTPUT;
var updatedTemplates = grunt.config(ephemeralUploadResultsProperty);
var oldTemplates = grunt.file.exists(outputFile)
? grunt.file.read(outputFile)
: {};

Object.keys(updatedTemplates).forEach(function (updatedTemplateKey) {
updatedTemplates[updatedTemplateKey] = Object.assign(
oldTemplates[updatedTemplateKey] || {},
updatedTemplates[updatedTemplateKey]
);

if (cleanOutput) {
delete updatedTemplates[updatedTemplateKey].htmlBody;
delete updatedTemplates[updatedTemplateKey].textBody;
delete updatedTemplates[updatedTemplateKey].htmlSrc;
delete updatedTemplates[updatedTemplateKey].textSrc;
}
});

grunt.file.write(outputFile, JSON.stringify(updatedTemplates, null, 2));
grunt.log.writeln("Updated template information written to " + outputFile);
});

// you can also get a JSON report of uploaded templates
grunt.registerTask('postmark-templates', ['postmark-templates-upload', 'postmark-templates-output']);
};
20 changes: 13 additions & 7 deletions tasks/grunt-postmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
* https://github.com/wildbit/grunt-postmark.git
*/

'use strict';

module.exports = function(grunt) {

'use strict';

grunt.registerMultiTask('postmark', 'Send emails through Postmark', function() {

var done = this.async();
var options = this.options();
var _data = this.data;

// Check for server token
if (!options.serverToken && !_data.serverToken) {
if (!options.serverToken && !_data.serverToken) {
grunt.fail.warn('Missing Postmark server token \n');
}

Expand All @@ -25,8 +25,8 @@ module.exports = function(grunt) {
if (this.files.length > 0) {

var message = {
'From': _data.from || options.from,
'To': _data.to || options.to,
'From': _data.from || options.from,
'To': _data.to || options.to,
'Subject': _data.subject || options.subject
};

Expand Down Expand Up @@ -56,7 +56,7 @@ module.exports = function(grunt) {
handleResponse(err, response, done);
});
}

} else {
// Warn about no files being passed to task
grunt.log.warn('No src file found \n');
Expand All @@ -66,7 +66,13 @@ module.exports = function(grunt) {


function handleResponse(err, response, done) {
err ? errorMessage(err) : successMessage(response);
if (err) {
errorMessage(err);

} else {
successMessage(response);
}

done();
}

Expand Down
1 change: 1 addition & 0 deletions test/email.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello from grunt-postmark-templates