├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── gulpfile.js ├── index.js ├── lib ├── execute.js ├── gulp-email.js └── utils.js ├── package.json └── test ├── lib ├── gulp-email.js └── utils.js └── mocha.opts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | demo 3 | npm-debug.log -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "undef": true, 4 | "browser": true, 5 | "globals": { 6 | "spyOnEvent": false, 7 | "spyOn": false, 8 | "define": false, 9 | "require": true, 10 | "setTimeout": false, 11 | "describe": false, 12 | "beforeEach": false, 13 | "afterEach": false, 14 | "setFixtures": false, 15 | "expect": false, 16 | "it": false, 17 | "xit": false 18 | }, 19 | "sub": true, 20 | "predef" : [ 21 | "FB", 22 | "yOSON", 23 | "$", 24 | "jQuery", 25 | "_", 26 | "log", 27 | "colorLog", 28 | "console", 29 | "warn", 30 | "echo", 31 | "debug", 32 | "success", 33 | "notice", 34 | "Cookie", 35 | "tmp", 36 | "browser", 37 | "arguments_", 38 | "gMap", 39 | "latitud", 40 | "longitud", 41 | "saveCookieEstado", 42 | "InfoBox", 43 | "NumberFormat", 44 | "MarkerClusterer", 45 | "style", 46 | "bottom", 47 | "height", 48 | "width", 49 | "isMobile", 50 | "trackAnalytics", 51 | "google", 52 | "GMaps", 53 | "ScrollInf", 54 | "module", 55 | "configuration" 56 | ], 57 | "eqeqeq" : false, // esto es el casi el diablo, hay que ponerle false 58 | "eqnull" : false, // esto es el casi el diablo, hay que ponerle false 59 | "loopfunc" : true, // esto es el diablo, hay que ponerle false 60 | "smarttabs" : false //Mixed spaces and tabs 61 | } 62 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | support 3 | benchmarks 4 | examples 5 | lib-cov 6 | coverage 7 | .git 8 | .gitmodules 9 | .travis.yml 10 | History.md 11 | Makefile 12 | test/ 13 | support/ 14 | benchmarks/ 15 | examples/ 16 | node_modules/ 17 | demo/ 18 | npm-debug.log -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jan Sanchez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Gulp Email [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] 3 | 4 | > A gulp plugin to send emails with or without attachments from a stream of html. 5 | 6 | 7 | ## Getting Started 8 | 9 | #### Install: 10 | 11 | ``` 12 | npm install --save-dev gulp-email 13 | ``` 14 | 15 | #### How to use: 16 | 17 | For example, using mailgun.com(registration it's free and you can send up to 10,000 emails every day.) 18 | 19 | Sending an email like report HTML and attaching a file. 20 | 21 | ```javascript 22 | var gulp = require('gulp'), 23 | email = require('gulp-email'); 24 | 25 | var options = { 26 | user: 'api:key-564dfgfead753fghef11c54c1fb', 27 | url: 'https://api.mailgun.net/v2/sandbox4825.mailgun.org/messages', 28 | form: { 29 | from: 'John Doe ', 30 | to: 'Fulano Mengano ', 31 | subject: 'The last dist', 32 | attachment: '@path/to/folder/dist.zip' 33 | } 34 | }; 35 | 36 | gulp.task('email', function () { 37 | return gulp.src(['./demo/reports/*.html']) 38 | .pipe(email(options)); 39 | }); 40 | ``` 41 | 42 | Sending an email without the content of a stream. 43 | 44 | 45 | ```javascript 46 | var gulp = require('gulp'), 47 | email = require('gulp-email'); 48 | 49 | var options = { 50 | user: 'api:key-564dfgfead753fghef11c54c1fb', 51 | url: 'https://api.mailgun.net/v2/sandbox4825.mailgun.org/messages', 52 | form: { 53 | from: 'John Doe ', 54 | to: 'Fulano Mengano ', 55 | cc: 'Regis Messac ', 56 | bcc: 'John Smith ', 57 | subject: 'You have an new email', 58 | text: 'text version' 59 | }, 60 | form_string: { 61 | html: '

Overwrite to html content of stream files.

' 62 | } 63 | }; 64 | 65 | gulp.task('email', function () { 66 | return gulp.src(['./demo/no-matter.html']) 67 | .pipe(email(options)); 68 | }); 69 | ``` 70 | 71 | For these examples I am using the API of mailgun.com(I recommend). In this first release only supports [mailgun API](http://documentation.mailgun.com/api-sending.html#sending "mailgun API") and is more than enough. 72 | 73 | 74 | 75 | [npm-url]: https://www.npmjs.org/package/gulp-email 76 | [npm-image]: http://img.shields.io/npm/v/gulp-email.svg 77 | 78 | [travis-url]: https://travis-ci.org/jansanchez/gulp-email 79 | [travis-image]: http://img.shields.io/travis/jansanchez/gulp-email.svg 80 | 81 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'), 4 | jshint = require('gulp-jshint'), 5 | clean = require('gulp-rimraf'), 6 | stylish = require('jshint-stylish'), 7 | complexity = require('gulp-complexity'); 8 | 9 | var path = { src: {} }; 10 | 11 | path.src.js = ['./index.js', './lib/*.js']; 12 | path.src.complexity = ['./index.js', './lib/*.js']; 13 | 14 | gulp.task('default', ['lint'], function() { 15 | console.log('All the Javascript.'); 16 | }); 17 | 18 | gulp.task('lint', function() { 19 | return gulp.src(path.src.js) 20 | .pipe(jshint('.jshintrc')) 21 | .pipe(jshint.reporter('jshint-stylish')) 22 | .pipe(jshint.reporter('fail')); 23 | }); 24 | 25 | gulp.task('watch', function () { 26 | var javascriptTasks = ['lint']; 27 | 28 | gulp.watch(path.src.js, javascriptTasks); 29 | }); 30 | 31 | /* 32 | gulp.task('complexity', function(){ 33 | return gulp.src(path.src.complexity) 34 | .pipe(complexity()); 35 | }); 36 | */ 37 | 38 | var email = require('./index'); 39 | 40 | var options = { 41 | user: 'api:key-bfc71afead753d73cef11c5485c1fd2b', 42 | url: 'https://api.mailgun.net/v3/sandbox4a0fe54c0059454483eff6624145da45.mailgun.org/messages', 43 | form: { 44 | from: 'Jamir Kaleb ', 45 | to: 'Jan Sanchez Hotmail ', 46 | subject: 'Nuevo mensaje de correo !!!', 47 | text: 'Texto plano del mensaje, esto se ve?' 48 | } 49 | }; 50 | 51 | 52 | gulp.task('email', function () { 53 | return gulp.src('./demo/html/*.html') 54 | .pipe(email(options, function(data, error){ 55 | console.log(data.message); 56 | })); 57 | }); 58 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | 5 | var GulpEmail = require('./lib/gulp-email'); 6 | 7 | 8 | /** 9 | * Expose library. 10 | */ 11 | 12 | module.exports = function(options, callback){ 13 | var gulpEmail = new GulpEmail(options, callback); 14 | return gulpEmail; 15 | }; 16 | -------------------------------------------------------------------------------- /lib/execute.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | 5 | var exec = require("child_process").exec; 6 | 7 | /* 8 | * Execute. 9 | * 10 | */ 11 | 12 | var Execute = function Execute(command, callback) { 13 | this.execute(command, callback); 14 | }; 15 | 16 | /** 17 | * Execute prototype. 18 | */ 19 | 20 | 21 | /** 22 | * Execute Command. 23 | */ 24 | Execute.prototype.execute = function(command, callback){ 25 | exec(command, function (error, stdout, stderr) { 26 | if (error) { 27 | callback(stdout, error); 28 | }else{ 29 | callback(JSON.parse(stdout), error); 30 | } 31 | }); 32 | }; 33 | 34 | 35 | /** 36 | * Expose `Execute`. 37 | */ 38 | module.exports = Execute; 39 | -------------------------------------------------------------------------------- /lib/gulp-email.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | 5 | var Transform = require('stream').Transform, 6 | Path = require("path"), 7 | Buffer = require('buffer').Buffer, 8 | File = require('vinyl'), 9 | chalk = require('chalk'), 10 | fs = require('fs'), 11 | utils = require('./utils'), 12 | Execute = require('./execute'), 13 | extend = require('util')._extend; 14 | 15 | 16 | /** 17 | * Gulp Email. 18 | */ 19 | function GulpEmail(opts, cb) { 20 | 21 | this.fullContent = ''; 22 | this.default = {}; 23 | this.cb = cb || this.callback; 24 | this.options = extend(this.default, opts); 25 | this.stream = new Transform({objectMode: true}); 26 | 27 | this.stream._transform = function(chunk, encoding, callback){ 28 | var fullPath = null, 29 | file = {}, 30 | relative = chunk.relative; 31 | 32 | file.base = chunk.base; 33 | file.contents = chunk.contents; 34 | 35 | file.extname = Path.extname(relative); 36 | file.basename = Path.basename(relative, file.extname); 37 | file.dirname = Path.dirname(relative); 38 | file.newDirname = utils.fixDirName(file.dirname); 39 | fullPath = file.newDirname + file.basename + file.extname; 40 | file.path = Path.join(chunk.base, fullPath); 41 | 42 | callback(null, self.readContent(file)); 43 | 44 | }; 45 | 46 | this.stream.on('end', function() { 47 | //console.log(self.fullContent); 48 | self.sendEmail(self.prepareCurl(self.fullContent)); 49 | }); 50 | 51 | var self = this; 52 | 53 | return this.stream; 54 | } 55 | 56 | GulpEmail.prototype.readContent = function(file){ 57 | var currentContent = file.contents.toString(); 58 | this.fullContent += currentContent; 59 | }; 60 | 61 | GulpEmail.prototype.prepareCurl = function(content){ 62 | var key, 63 | values, 64 | args = ['curl', '--no-buffer', '--show-error', '--silent'], 65 | settings = this.options, 66 | childrensCounter, 67 | request, 68 | haveTextHtml = false, 69 | subvalues; 70 | 71 | for (key in settings) { 72 | values = Array.isArray(settings[key]) ? settings[key] : [settings[key]]; 73 | values.forEach(function(value) { 74 | childrensCounter = 0; 75 | key = key.replace('_', '-'); 76 | if (key !== 'url') { 77 | args.push("--" + key); 78 | } 79 | if (true !== value) { 80 | if (typeof value === 'object') { 81 | for (var subkey in value) { 82 | subvalues = Array.isArray(value[subkey]) ? value[subkey] : [value[subkey]]; 83 | subvalues.forEach(function(subvalue) { 84 | childrensCounter++; 85 | if (childrensCounter !== 1) { 86 | args.push("--" + key); 87 | } 88 | args.push(subkey + "='" + subvalue + "'"); 89 | if (subkey === 'html') { 90 | haveTextHtml = true; 91 | } 92 | if (subkey === 'to') { 93 | console.log(chalk.yellow('Sending to: ') + chalk.yellow.bold(subvalue)); 94 | } 95 | }); 96 | } 97 | } else { 98 | args.push(value); 99 | } 100 | } 101 | }); 102 | } 103 | 104 | if (haveTextHtml === false) { 105 | args.push('--form-string'); 106 | content = content.replace(/'/g, '\"'); 107 | //console.log(content); 108 | args.push('html=\'' + content + '\''); 109 | } 110 | 111 | request = args.join(" "); 112 | //console.log(request); 113 | 114 | return request; 115 | }; 116 | 117 | GulpEmail.prototype.sendEmail = function(request){ 118 | var execute = new Execute(request, this.cb); 119 | }; 120 | 121 | GulpEmail.prototype.callback = function(data, error){ 122 | if (error) { 123 | console.log(error); 124 | }else{ 125 | console.log(data); 126 | } 127 | 128 | }; 129 | 130 | 131 | /** 132 | * Expose `GulpEmail`. 133 | */ 134 | 135 | module.exports = GulpEmail; 136 | 137 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utils. 3 | */ 4 | 5 | var Utils = { 6 | fixDirName: function (dirname){ 7 | var newDirname = ""; 8 | if (dirname.toString().indexOf(".") === -1) { 9 | newDirname = dirname + "/"; 10 | } 11 | return newDirname; 12 | }, 13 | getFolderName: function (base, dirname){ 14 | var arrayFolders = (base + dirname).match(/[a-zA-Z0-9_-]+\/+/gi), 15 | folderName = arrayFolders[arrayFolders.length -1]; 16 | folderName = folderName.replace("/", ""); 17 | return folderName; 18 | } 19 | }; 20 | 21 | 22 | /** 23 | * Expose `Utils`. 24 | */ 25 | 26 | module.exports = Utils; 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-email", 3 | "version": "0.0.7", 4 | "description": "A gulp plugin to send emails with or without attachments from a stream of html.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/jansanchez/gulp-email.git" 12 | }, 13 | "keywords": [ 14 | "gulpfriendly", 15 | "gulpplugin", 16 | "gulp", 17 | "email", 18 | "mailgun", 19 | "attach" 20 | ], 21 | "author": "Jan Sanchez", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/jansanchez/gulp-email/issues" 25 | }, 26 | "homepage": "https://github.com/jansanchez/gulp-email", 27 | "devDependencies": { 28 | "mocha": "~1.21.4", 29 | "should": "~4.0.4", 30 | "gulp": "~3.8.7", 31 | "gulp-complexity": "~0.2.1", 32 | "gulp-jshint": "~1.8.4", 33 | "jshint-stylish": "~0.4.0", 34 | "gulp-rimraf": "^0.1.0" 35 | }, 36 | "dependencies": { 37 | "chalk": "^1.1.1", 38 | "vinyl": "~0.3.2" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/lib/gulp-email.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test: gulpEmail 3 | */ 4 | 5 | var gulpEmail = require('../../lib/gulp-email'); 6 | 7 | describe('Gulp Email', function(){ 8 | 9 | var gulpEmail, 10 | options = {}; 11 | 12 | beforeEach(function(){ 13 | 14 | }); 15 | 16 | it.skip('uno.', function(done){ 17 | 18 | }); 19 | 20 | 21 | }); 22 | 23 | -------------------------------------------------------------------------------- /test/lib/utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test: Utils 3 | */ 4 | 5 | var utils = require('../../lib/utils'); 6 | 7 | 8 | describe('Utils', function(){ 9 | 10 | var file = { 11 | dirname : {}, 12 | newDirname : {} 13 | }; 14 | 15 | beforeEach(function(){ 16 | file.dirname.uno = "main/modules"; 17 | file.dirname.dos = "."; 18 | 19 | file.path = {p1: "/demo/source/", p2: "modules/default/index/"}; 20 | 21 | 22 | file.newDirname.uno = "main/modules/"; 23 | file.newDirname.dos = ""; 24 | 25 | file.newPath = "index"; 26 | }); 27 | 28 | describe('fixDirName', function(){ 29 | 30 | it('Debe poder normalizar las rutas de las carpetas.', function(){ 31 | utils.fixDirName(file.dirname.uno).should.be.equal(file.newDirname.uno); 32 | utils.fixDirName(file.dirname.dos).should.be.equal(file.newDirname.dos); 33 | }); 34 | 35 | }); 36 | 37 | describe('getFolderName', function(){ 38 | it('Debe poder obtener el nombre de la última carpeta.', function(){ 39 | utils.getFolderName(file.path.p1, file.path.p2).should.be.equal(file.newPath); 40 | }); 41 | }); 42 | 43 | }); 44 | 45 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require assert 2 | --require should 3 | --reporter spec 4 | --recursive --------------------------------------------------------------------------------