├── .gitignore ├── .npmignore ├── .prettierrc.js ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE ├── package.json ├── README.md ├── src └── nodemailer-html-to-text.js └── test └── nodemailer-html-to-text-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .travis.yml 2 | .jshintrc 3 | test -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 160, 3 | tabWidth: 4, 4 | singleQuote: true, 5 | endOfLine: 'lf', 6 | trailingComma: 'none', 7 | arrowParens: 'avoid' 8 | }; 9 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "indent": 4, 3 | "node": true, 4 | "globalstrict": true, 5 | "evil": true, 6 | "unused": true, 7 | "undef": true, 8 | "newcap": true, 9 | "esnext": true, 10 | "curly": true, 11 | "eqeqeq": true, 12 | "expr": true, 13 | 14 | "predef": [ 15 | "describe", 16 | "it", 17 | "beforeEach", 18 | "afterEach" 19 | ] 20 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '10' 4 | - '12' 5 | - '14' 6 | - '16' 7 | 8 | before_install: 9 | - npm install -g grunt-cli 10 | 11 | notifications: 12 | email: 13 | recipients: 14 | - andris@kreata.ee 15 | on_success: change 16 | on_failure: change 17 | webhooks: 18 | urls: 19 | - https://webhooks.gitter.im/e/0ed18fd9b3e529b3c2cc 20 | on_success: change # options: [always|never|change] default: always 21 | on_failure: always # options: [always|never|change] default: always 22 | on_start: false # default: false 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## v3.0.0 2021-04-22 4 | 5 | - Upgraded node-html-text to 7.1.1 - introduced changes in option handling, please check https://github.com/html-to-text/node-html-to-text for changes 6 | - Updated dev dependencies 7 | - Deprecate Node versions < 10.23 8 | 9 | ## v2.2.0 2018-06-26 10 | 11 | - Upgraded node-html-text to 4.0.0 12 | - Updated dev dependencies 13 | - Deprecate Node versions < 4 14 | 15 | ## v2.1.0 2016-04-11 16 | 17 | - Upgraded node-html-text 18 | 19 | ## v1.0.2 2015-07-20 20 | 21 | - Remove inlined picture references from the plain text (fintura) 22 | 23 | ## v1.0.1 2015-03-20 24 | 25 | - Updated html-to-text 26 | 27 | ## v1.0.0 2014-07-30 28 | 29 | - Initial 30 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | // Project configuration. 6 | grunt.initConfig({ 7 | jshint: { 8 | all: ['src/*.js', 'test/*.js'], 9 | options: { 10 | jshintrc: '.jshintrc' 11 | } 12 | }, 13 | 14 | mochaTest: { 15 | all: { 16 | options: { 17 | reporter: 'spec' 18 | }, 19 | src: ['test/*-test.js'] 20 | } 21 | } 22 | }); 23 | 24 | // Load the plugin(s) 25 | grunt.loadNpmTasks('grunt-contrib-jshint'); 26 | grunt.loadNpmTasks('grunt-mocha-test'); 27 | 28 | // Tasks 29 | grunt.registerTask('default', ['jshint', 'mochaTest']); 30 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Andris Reinman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodemailer-html-to-text", 3 | "version": "3.0.0", 4 | "description": "Generate text content from html for Nodemailer e-mails", 5 | "main": "src/nodemailer-html-to-text.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "grunt" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/andris9/nodemailer-html-to-text.git" 15 | }, 16 | "keywords": [ 17 | "Nodemailer" 18 | ], 19 | "author": "Andris Reinman", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/andris9/nodemailer-html-to-text/issues" 23 | }, 24 | "homepage": "https://github.com/andris9/nodemailer-html-to-text", 25 | "dependencies": { 26 | "html-to-text": "7.1.1" 27 | }, 28 | "devDependencies": { 29 | "chai": "4.3.4", 30 | "grunt": "1.3.0", 31 | "grunt-contrib-jshint": "3.0.0", 32 | "grunt-mocha-test": "0.13.3", 33 | "mocha": "8.3.2" 34 | }, 35 | "engines": { 36 | "node": ">= 10.23.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nodemailer plugin to generate text content from HTML 2 | 3 | This applies to Nodemailer v1.1+. The plugin checks if there is no `text` option specified and populates it based on the `html` value. 4 | 5 | This plugin is meant as replacement for the `generateTextFromHTML` option that was removed from Nodemailer 1.0 6 | 7 | ## Install 8 | 9 | Install from npm 10 | 11 | npm install nodemailer-html-to-text --save 12 | 13 | ## Usage 14 | 15 | Load the `htmlToText` function 16 | 17 | ```javascript 18 | var htmlToText = require('nodemailer-html-to-text').htmlToText; 19 | ``` 20 | 21 | Attach it as a 'compile' handler for a nodemailer transport object 22 | 23 | ```javascript 24 | nodemailerTransport.use('compile', htmlToText(options)) 25 | ``` 26 | 27 | Where 28 | 29 | * **options** - includes options for the [html-to-text](https://www.npmjs.org/package/html-to-text) converter 30 | 31 | ## Example 32 | 33 | ```javascript 34 | var nodemailer = require('nodemailer'); 35 | var htmlToText = require('nodemailer-html-to-text').htmlToText; 36 | var transporter = nodemailer.createTransport(); 37 | transporter.use('compile', htmlToText()); 38 | transporter.sendMail({ 39 | from: 'me@example.com', 40 | to: 'receiver@example.com', 41 | html: 'Hello world!' 42 | }); 43 | ``` 44 | 45 | ## License 46 | 47 | **MIT** -------------------------------------------------------------------------------- /src/nodemailer-html-to-text.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const converter = require('html-to-text'); 4 | 5 | module.exports.htmlToText = function (options) { 6 | options = options || {}; 7 | 8 | return function (mail, done) { 9 | const handler = new HTMLToText(options); 10 | handler.process(mail, done); 11 | }; 12 | }; 13 | 14 | function HTMLToText(options) { 15 | this._options = {}; 16 | 17 | // create a shallow copy of the passed options 18 | Object.keys(options || {}).forEach( 19 | function (key) { 20 | this._options[key] = options[key]; 21 | }.bind(this) 22 | ); 23 | } 24 | 25 | HTMLToText.prototype.process = function (mail, done) { 26 | if (!mail || !mail.data || !mail.data.html || mail.data.text) { 27 | return done(); 28 | } 29 | 30 | mail.resolveContent( 31 | mail.data, 32 | 'html', 33 | function (err, html) { 34 | if (err) { 35 | return done(err); 36 | } 37 | try { 38 | mail.data.text = converter.htmlToText(html, this._options); 39 | mail.data.text = mail.data.text.replace(/(\n)\[cid:.*?\] |\[cid:.*?\]/g, '$1'); 40 | } catch (E) { 41 | return done(E); 42 | } 43 | done(); 44 | }.bind(this) 45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /test/nodemailer-html-to-text-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai'); 4 | var htmlToText = require('../src/nodemailer-html-to-text').htmlToText; 5 | 6 | var expect = chai.expect; 7 | chai.config.includeStack = true; 8 | 9 | describe('nodemailer-html-to-text tests', function () { 10 | it('should set text from html string', function (done) { 11 | var plugin = htmlToText(); 12 | var mail = { 13 | data: { 14 | html: '

Tere, tere

vana kere!

' 15 | }, 16 | resolveContent: function (obj, key, cb) { 17 | cb(null, obj[key]); 18 | } 19 | }; 20 | plugin(mail, function (err) { 21 | expect(err).to.not.exist; 22 | expect(mail.data.text).to.equal('Tere, tere\n\nvana kere!'); 23 | done(); 24 | }); 25 | }); 26 | 27 | it('should remove the inlined picture reference including the empty space behind a line break', function (done) { 28 | var plugin = htmlToText(); 29 | var mail = { 30 | data: { 31 | html: '

Tere, tere

vana kere!

' 32 | }, 33 | resolveContent: function (obj, key, cb) { 34 | cb(null, obj[key]); 35 | } 36 | }; 37 | plugin(mail, function (err) { 38 | expect(err).to.not.exist; 39 | expect(mail.data.text).to.equal('Tere, tere\n\nvana kere!'); 40 | done(); 41 | }); 42 | }); 43 | 44 | it('should remove the inlined picture reference and keep the empty space without line break', function (done) { 45 | var plugin = htmlToText(); 46 | var mail = { 47 | data: { 48 | html: '

Tere, tere

vana kere!

' 49 | }, 50 | resolveContent: function (obj, key, cb) { 51 | cb(null, obj[key]); 52 | } 53 | }; 54 | plugin(mail, function (err) { 55 | expect(err).to.not.exist; 56 | expect(mail.data.text).to.equal('Tere, tere\n\nvana kere!'); 57 | done(); 58 | }); 59 | }); 60 | 61 | it('should set text from html buffer', function (done) { 62 | var plugin = htmlToText(); 63 | var mail = { 64 | data: { 65 | html: Buffer.from('

Tere, tere

vana kere!

') 66 | }, 67 | resolveContent: function (obj, key, cb) { 68 | cb(null, obj[key]); 69 | } 70 | }; 71 | plugin(mail, function (err) { 72 | expect(err).to.not.exist; 73 | expect(mail.data).to.deep.equal({ 74 | html: Buffer.from('

Tere, tere

vana kere!

'), 75 | text: 'Tere, tere\n\nvana kere!' 76 | }); 77 | done(); 78 | }); 79 | }); 80 | 81 | it('should return an error', function (done) { 82 | var plugin = htmlToText(); 83 | var mail = { 84 | data: { 85 | html: 'test' 86 | }, 87 | resolveContent: function (obj, key, cb) { 88 | cb(new Error('fail')); 89 | } 90 | }; 91 | plugin(mail, function (err) { 92 | expect(err).to.exist; 93 | done(); 94 | }); 95 | }); 96 | }); 97 | --------------------------------------------------------------------------------