├── .gitignore ├── LICENSE ├── README.md ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .*.swp 3 | ._* 4 | .DS_Store 5 | .git 6 | .hg 7 | .npmrc 8 | .lock-wscript 9 | .wafpickle-* 10 | config.gypi 11 | CVS 12 | npm-debug.log 13 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jose Luis 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 | # Simple Parse Server SMTP Email Adapter 2 | 3 | With this adapter you can send email for reset password and email verification in parse with SMTP access and custom templates, I am doing methods for support email verification, and templates for reset password pages :) 4 | 5 | ### Installation 6 | 7 | Install npm module in your parse server project 8 | 9 | ```sh 10 | $ npm install --save simple-parse-smtp-adapter 11 | ``` 12 | 13 | ### Use 14 | 15 | In the configuration of your parse server you must pass `simple-parse-smtp-adapter` as email adapter and set your SMTP access for send emails also the path to your jade template and its less file. 16 | 17 | This is an example using parse server as express module: 18 | 19 | ```js 20 | "use strict"; 21 | 22 | const Express = require('express'); 23 | const ParseServer = require('parse-server').ParseServer; 24 | 25 | const app = Express(); 26 | const APP_PORT = 1337; 27 | 28 | let options = { 29 | 30 | }; 31 | 32 | let api = new ParseServer({ 33 | appName: "Parse Test", 34 | appId: "12345", 35 | masterKey: "abcde12345", 36 | serverURL: "http://localhost:1337/parse", 37 | publicServerURL: "http://localhost:1337/parse", 38 | databaseURI: "mongodb://user:pass@host:27017/parse", 39 | port: APP_PORT, 40 | //This is the config for email adapter 41 | emailAdapter: { 42 | module: "simple-parse-smtp-adapter", 43 | options: { 44 | service:'Gmail', // required 45 | clientId:'your_clientid_get_from_console_google_developers', 46 | clientSecret:'your_clientsecret_get_from_console_google_developers', 47 | refreshToken:'your_refresh_token_get_from_console_google_developers', 48 | accessToken:'your_access_token_get_from_console_google_developers', 49 | fromAddress: 'your@sender.address', 50 | user: 'email@email.com', //#"required for service SMTP" 51 | //password: 'AwesomePassword', //#"required for service SMTP" 52 | //host: 'your.smtp.host', //#"required for service SMTP" 53 | //isSSL: true, //True or false if you are using ssl //#"required for service SMTP" 54 | //port: 465, //SSL port or another port //#"required for service SMTP" 55 | name: 'your domain name', // optional, used for identifying to the server 56 | //Somtimes the user email is not in the 'email' field, the email is search first in 57 | //email field, then in username field, if you have the user email in another field 58 | //You can specify here 59 | emailField: 'username', 60 | templates: { 61 | //This template is used only for reset password email 62 | resetPassword: { 63 | //Path to your template 64 | template: __dirname + '/views/email/reset-password', 65 | //Subject for this email 66 | subject: 'Reset your password' 67 | }, 68 | verifyEmail: { 69 | template: __dirname + '/views/email/verify-email', 70 | subject: 'Verify Email' 71 | } 72 | } 73 | } 74 | } 75 | }); 76 | 77 | /** 78 | * Parse Server endpoint 79 | */ 80 | app.use('/parse', api); 81 | 82 | app.listen(APP_PORT, function () { 83 | console.log(`Parse Server Ready and listening on port ${APP_PORT}`); 84 | }); 85 | ``` 86 | 87 | ### Template 88 | The path you pass to the email adapter must be a directory and not a file, this path must contain 2 mandatory files `html.jade` and `style.less` you can do your template as you like with the [CSS rules that emails supports](https://www.campaignmonitor.com/css/) in the template you can use 3 variables: 89 | 90 | - appName //This is the name of your parse app 91 | - link //This is the link for reset the password 92 | - user //This is a Parse object with the current user, so you can use any field in your User class of parse for example the user name `#{user.get('username')}` 93 | 94 | ### Contributing 95 | This module is pull request friendly in the develop branch feel free of send new features or bug fixes. 96 | 97 | If you find a bug please open an issue. 98 | 99 | ### License MIT 100 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require('path'); 3 | const nodemailer = require("nodemailer"); 4 | const EmailTemplate = require('email-templates').EmailTemplate; 5 | 6 | let SimpleParseSmtpAdapter = (adapterOptions) => { 7 | 8 | if(!adapterOptions && adapterOptions.service=='Gmail'){ 9 | if (!adapterOptions || 10 | !adapterOptions.service|| 11 | !adapterOptions.type || 12 | !adapterOptions.user || 13 | !adapterOptions.clientId || 14 | !adapterOptions.clientSecret|| 15 | !adapterOptions.refreshToken || 16 | !adapterOptions.accessToken ) { 17 | throw 'SimpleParseSMTPAdapter requires service,type, user, clientId,clientSecret,refreshToken and accessToken'; 18 | } 19 | } 20 | else if(!adapterOptions && adapterOptions.service=='SMTP'){ 21 | if (!adapterOptions || !adapterOptions.user || !adapterOptions.password || !adapterOptions.host || !adapterOptions.fromAddress ) { 22 | throw 'SimpleParseSMTPAdapter requires user, password, host, and fromAddress'; 23 | } 24 | }else{ 25 | throw 'SimpleParseSMTPAdapter please choose service Gmail or SMTP'; 26 | } 27 | 28 | /** 29 | * Creates trasporter for send emails with OAuth2 Gmail 30 | */ 31 | let transporterOAuth2Gmail = nodemailer.createTransport({ 32 | service: adapterOptions.service, 33 | auth: { 34 | type: adapterOptions.type, 35 | user: adapterOptions.user, 36 | clientId: adapterOptions.clientId, 37 | clientSecret: adapterOptions.clientSecret, 38 | refreshToken: adapterOptions.refreshToken, 39 | accessToken: adapterOptions.refreshToken, 40 | expires: adapterOptions.expires 41 | } 42 | }); 43 | 44 | /** 45 | * Creates trasporter for send emails with OAuth2 Gmail 46 | */ 47 | let transporter = nodemailer.createTransport({ 48 | host: adapterOptions.host, 49 | port: adapterOptions.port, 50 | secure: adapterOptions.isSSL, 51 | name: adapterOptions.name || '127.0.0.1', 52 | auth: { 53 | user: adapterOptions.user, 54 | pass: adapterOptions.password 55 | }, 56 | tls: { 57 | rejectUnauthorized: adapterOptions.isTlsRejectUnauthorized !== undefined ? adapterOptions.isTlsRejectUnauthorized : true 58 | } 59 | }); 60 | 61 | /** 62 | * When emailField is defined in adapterOptines return that field 63 | * if not return the field email and if is undefined returns username 64 | * 65 | * @param Parse Object user 66 | * @return String email 67 | */ 68 | let getUserEmail = (user) => { 69 | let email = user.get('email') || user.get('username'); 70 | 71 | if (adapterOptions.emailField) { 72 | email = user.get(adapterOptions.emailField); 73 | } 74 | 75 | return email; 76 | }; 77 | 78 | /** 79 | * Return an email template with data rendered using email-templates module 80 | * check module docs: https://github.com/niftylettuce/node-email-templates 81 | * 82 | * @param String template path template 83 | * @param Object data object with data for use in template 84 | */ 85 | let renderTemplate = (template, data) => { 86 | let templateDir = template; 87 | let html = new EmailTemplate(templateDir); 88 | 89 | return new Promise((resolve, reject) => { 90 | html.render(data, (err, result) => { 91 | if (err) { 92 | console.log(err) 93 | reject(err); 94 | } else { 95 | resolve(result); 96 | } 97 | }); 98 | }); 99 | }; 100 | 101 | /** 102 | * Parse use this function by default for sends emails 103 | * @param mail This object contain to address, subject and email text in plain text 104 | * @returns {Promise} 105 | */ 106 | let sendMail = (mail) => { 107 | let mailOptions = { 108 | to: mail.to, 109 | html: mail.text, 110 | subject: mail.subject, 111 | from: adapterOptions.fromAddress 112 | }; 113 | 114 | return new Promise((resolve, reject) => { 115 | 116 | if(adapterOptions.service=='SMTP'){ 117 | transporter.sendMail(mailOptions, (error, info) => { 118 | if(error) { 119 | console.log(error) 120 | reject(error); 121 | } else { 122 | resolve(info); 123 | } 124 | }); 125 | } 126 | else if(adapterOptions.service=='Gmail'){ 127 | transporterOAuth2Gmail.sendMail(mailOptions, (error, info) => { 128 | if(error) { 129 | console.log(error) 130 | reject(error); 131 | } else { 132 | resolve(info); 133 | } 134 | }); 135 | } 136 | 137 | }); 138 | }; 139 | 140 | /** 141 | * When this method is available parse use for send email for reset password 142 | * @param data This object contain {appName}, {link} and {user} user is an object parse of User class 143 | * @returns {Promise} 144 | */ 145 | let sendPasswordResetEmail = (data) => { 146 | let mail = { 147 | subject: 'Reset Password', 148 | to: getUserEmail(data.user) 149 | }; 150 | 151 | if (adapterOptions.templates && adapterOptions.templates.resetPassword) { 152 | 153 | return renderTemplate(adapterOptions.templates.resetPassword.template, data).then((result) => { 154 | mail.text = result.html; 155 | mail.subject = adapterOptions.templates.resetPassword.subject; 156 | 157 | return sendMail(mail); 158 | }, (e) => { 159 | 160 | return new Promise((resolve, reject) => { 161 | console.log(e) 162 | reject(e); 163 | }); 164 | }); 165 | 166 | } else { 167 | mail.text = data.link; 168 | 169 | return sendMail(mail); 170 | } 171 | }; 172 | 173 | /** 174 | * When this method is available parse use for send email for email verification 175 | * @param data This object contain {appName}, {link} and {user} user is an object parse of User class 176 | * @returns {Promise} 177 | */ 178 | let sendVerificationEmail = (data) => { 179 | let mail = { 180 | subject: 'Verify Email', 181 | to: getUserEmail(data.user) 182 | }; 183 | 184 | if (adapterOptions.templates && adapterOptions.templates.verifyEmail) { 185 | 186 | return renderTemplate(adapterOptions.templates.verifyEmail.template, data).then((result) => { 187 | mail.text = result.html; 188 | mail.subject = adapterOptions.templates.verifyEmail.subject; 189 | 190 | return sendMail(mail); 191 | }, (e) => { 192 | 193 | return new Promise((resolve, reject) => { 194 | console.log(e); 195 | reject(e); 196 | }); 197 | }); 198 | 199 | } else { 200 | mail.text = data.link; 201 | 202 | return sendMail(mail); 203 | } 204 | }; 205 | 206 | return Object.freeze({ 207 | sendMail: sendMail, 208 | renderTemplate: renderTemplate, 209 | sendPasswordResetEmail: sendPasswordResetEmail, 210 | sendVerificationEmail: sendVerificationEmail 211 | }); 212 | }; 213 | 214 | module.exports = SimpleParseSmtpAdapter; 215 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-parse-smtp-adapter", 3 | "version": "1.0.9", 4 | "description": "Send custom emails from parse with SMTP access", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js" 9 | }, 10 | "keywords": [ 11 | "parse", 12 | "email", 13 | "adapter", 14 | "templates", 15 | "parse.com" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/lcortess/simple-parse-smtp-adapter" 20 | }, 21 | "author": "Jose Luis (http://lcortes.net), Muhamad Muchlis ", 22 | "license": "MIT", 23 | "dependencies": { 24 | "email-templates": "^2.4.1", 25 | "jade": "^1.11.0", 26 | "less": "^2.7.1", 27 | "nodemailer": "^3.1.7", 28 | "path": "^0.12.7", 29 | "xoauth2": "^1.2.0" 30 | } 31 | } 32 | --------------------------------------------------------------------------------