├── .codeclimate.yml
├── .env_sample
├── .eslintignore
├── .eslintrc.yml
├── .github
└── PULL_REQUEST_TEMPLATE
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── USAGE.md
├── examples
├── simple.js
└── test.txt
├── package.json
├── src
└── sendgrid-transport.js
└── test
├── license-test.js
├── sendgrid-transport-test.js
└── test.js
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | duplication:
4 | enabled: true
5 | config:
6 | languages:
7 | - javascript
8 | eslint:
9 | enabled: true
10 | fixme:
11 | enabled: true
12 | ratings:
13 | paths:
14 | - "**.js"
15 | exclude_paths:
16 | - node_modules/
17 | - test/
18 |
--------------------------------------------------------------------------------
/.env_sample:
--------------------------------------------------------------------------------
1 | export SENDGRID_API_KEY=''
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*{.,-}min.js
2 |
--------------------------------------------------------------------------------
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | ---
2 | parserOptions:
3 | sourceType: module
4 | ecmaFeatures:
5 | jsx: true
6 |
7 | env:
8 | amd: true
9 | browser: true
10 | es6: true
11 | jquery: true
12 | node: true
13 |
14 | # http://eslint.org/docs/rules/
15 | rules:
16 | # Possible Errors
17 | no-await-in-loop: off
18 | no-cond-assign: error
19 | no-console: off
20 | no-constant-condition: error
21 | no-control-regex: error
22 | no-debugger: error
23 | no-dupe-args: error
24 | no-dupe-keys: error
25 | no-duplicate-case: error
26 | no-empty-character-class: error
27 | no-empty: error
28 | no-ex-assign: error
29 | no-extra-boolean-cast: error
30 | no-extra-parens: off
31 | no-extra-semi: error
32 | no-func-assign: error
33 | no-inner-declarations:
34 | - error
35 | - functions
36 | no-invalid-regexp: error
37 | no-irregular-whitespace: error
38 | no-negated-in-lhs: error
39 | no-obj-calls: error
40 | no-prototype-builtins: off
41 | no-regex-spaces: error
42 | no-sparse-arrays: error
43 | no-template-curly-in-string: off
44 | no-unexpected-multiline: error
45 | no-unreachable: error
46 | no-unsafe-finally: off
47 | no-unsafe-negation: off
48 | use-isnan: error
49 | valid-jsdoc: off
50 | valid-typeof: error
51 |
52 | # Best Practices
53 | accessor-pairs: error
54 | array-callback-return: off
55 | block-scoped-var: off
56 | class-methods-use-this: off
57 | complexity:
58 | - error
59 | - 6
60 | consistent-return: off
61 | curly: off
62 | default-case: off
63 | dot-location: off
64 | dot-notation: off
65 | eqeqeq: error
66 | guard-for-in: error
67 | no-alert: error
68 | no-caller: error
69 | no-case-declarations: error
70 | no-div-regex: error
71 | no-else-return: off
72 | no-empty-function: off
73 | no-empty-pattern: error
74 | no-eq-null: error
75 | no-eval: error
76 | no-extend-native: error
77 | no-extra-bind: error
78 | no-extra-label: off
79 | no-fallthrough: error
80 | no-floating-decimal: off
81 | no-global-assign: off
82 | no-implicit-coercion: off
83 | no-implied-eval: error
84 | no-invalid-this: off
85 | no-iterator: error
86 | no-labels:
87 | - error
88 | - allowLoop: true
89 | allowSwitch: true
90 | no-lone-blocks: error
91 | no-loop-func: error
92 | no-magic-number: off
93 | no-multi-spaces: off
94 | no-multi-str: off
95 | no-native-reassign: error
96 | no-new-func: error
97 | no-new-wrappers: error
98 | no-new: error
99 | no-octal-escape: error
100 | no-octal: error
101 | no-param-reassign: off
102 | no-proto: error
103 | no-redeclare: error
104 | no-restricted-properties: off
105 | no-return-assign: error
106 | no-return-await: off
107 | no-script-url: error
108 | no-self-assign: off
109 | no-self-compare: error
110 | no-sequences: off
111 | no-throw-literal: off
112 | no-unmodified-loop-condition: off
113 | no-unused-expressions: error
114 | no-unused-labels: off
115 | no-useless-call: error
116 | no-useless-concat: error
117 | no-useless-escape: off
118 | no-useless-return: off
119 | no-void: error
120 | no-warning-comments: off
121 | no-with: error
122 | prefer-promise-reject-errors: off
123 | radix: error
124 | require-await: off
125 | vars-on-top: off
126 | wrap-iife: error
127 | yoda: off
128 |
129 | # Strict
130 | strict: off
131 |
132 | # Variables
133 | init-declarations: off
134 | no-catch-shadow: error
135 | no-delete-var: error
136 | no-label-var: error
137 | no-restricted-globals: off
138 | no-shadow-restricted-names: error
139 | no-shadow: off
140 | no-undef-init: error
141 | no-undef: off
142 | no-undefined: off
143 | no-unused-vars: off
144 | no-use-before-define: off
145 |
146 | # Node.js and CommonJS
147 | callback-return: error
148 | global-require: error
149 | handle-callback-err: error
150 | no-mixed-requires: off
151 | no-new-require: off
152 | no-path-concat: error
153 | no-process-env: off
154 | no-process-exit: error
155 | no-restricted-modules: off
156 | no-sync: off
157 |
158 | # Stylistic Issues
159 | array-bracket-spacing: off
160 | block-spacing: off
161 | brace-style: off
162 | camelcase: off
163 | capitalized-comments: off
164 | comma-dangle:
165 | - error
166 | - never
167 | comma-spacing: off
168 | comma-style: off
169 | computed-property-spacing: off
170 | consistent-this: off
171 | eol-last: off
172 | func-call-spacing: off
173 | func-name-matching: off
174 | func-names: off
175 | func-style: off
176 | id-length: off
177 | id-match: off
178 | indent: off
179 | jsx-quotes: off
180 | key-spacing: off
181 | keyword-spacing: off
182 | line-comment-position: off
183 | linebreak-style: off
184 | lines-around-comment: off
185 | lines-around-directive: off
186 | max-depth: off
187 | max-len: off
188 | max-nested-callbacks: off
189 | max-params: off
190 | max-statements-per-line: off
191 | max-statements:
192 | - error
193 | - 30
194 | multiline-ternary: off
195 | new-cap: off
196 | new-parens: off
197 | newline-after-var: off
198 | newline-before-return: off
199 | newline-per-chained-call: off
200 | no-array-constructor: off
201 | no-bitwise: off
202 | no-continue: off
203 | no-inline-comments: off
204 | no-lonely-if: off
205 | no-mixed-operators: off
206 | no-mixed-spaces-and-tabs: off
207 | no-multi-assign: off
208 | no-multiple-empty-lines: off
209 | no-negated-condition: off
210 | no-nested-ternary: off
211 | no-new-object: off
212 | no-plusplus: off
213 | no-restricted-syntax: off
214 | no-spaced-func: off
215 | no-tabs: off
216 | no-ternary: off
217 | no-trailing-spaces: off
218 | no-underscore-dangle: off
219 | no-unneeded-ternary: off
220 | object-curly-newline: off
221 | object-curly-spacing: off
222 | object-property-newline: off
223 | one-var-declaration-per-line: off
224 | one-var: off
225 | operator-assignment: off
226 | operator-linebreak: off
227 | padded-blocks: off
228 | quote-props: off
229 | quotes: off
230 | require-jsdoc: off
231 | semi-spacing: off
232 | semi: off
233 | sort-keys: off
234 | sort-vars: off
235 | space-before-blocks: off
236 | space-before-function-paren: off
237 | space-in-parens: off
238 | space-infix-ops: off
239 | space-unary-ops: off
240 | spaced-comment: off
241 | template-tag-spacing: off
242 | unicode-bom: off
243 | wrap-regex: off
244 |
245 | # ECMAScript 6
246 | arrow-body-style: off
247 | arrow-parens: off
248 | arrow-spacing: off
249 | constructor-super: off
250 | generator-star-spacing: off
251 | no-class-assign: off
252 | no-confusing-arrow: off
253 | no-const-assign: off
254 | no-dupe-class-members: off
255 | no-duplicate-imports: off
256 | no-new-symbol: off
257 | no-restricted-imports: off
258 | no-this-before-super: off
259 | no-useless-computed-key: off
260 | no-useless-constructor: off
261 | no-useless-rename: off
262 | no-var: off
263 | object-shorthand: off
264 | prefer-arrow-callback: off
265 | prefer-const: off
266 | prefer-destructuring: off
267 | prefer-numeric-literals: off
268 | prefer-rest-params: off
269 | prefer-reflect: off
270 | prefer-spread: off
271 | prefer-template: off
272 | require-yield: off
273 | rest-spread-spacing: off
274 | sort-imports: off
275 | symbol-description: off
276 | template-curly-spacing: off
277 | yield-star-spacing: off
278 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE:
--------------------------------------------------------------------------------
1 |
10 | # Fixes #
11 |
12 | ### Checklist
13 | - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar)
14 | - [ ] I have read the [Contribution Guide] and my PR follows them.
15 | - [ ] I updated my branch with the master branch.
16 | - [ ] I have added tests that prove my fix is effective or that my feature works
17 | - [ ] I have added necessary documentation about the functionality in the appropriate .md file
18 | - [ ] I have added in line documentation to the code I modified
19 |
20 | ### Short description of what this PR does:
21 | -
22 | -
23 |
24 | If you have questions, please send an email to [Sendgrid](mailto:dx@sendgrid.com), or file a Github Issue in this repository.
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by http://www.gitignore.io
2 |
3 | ### Node ###
4 | # Logs
5 | logs
6 | *.log
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 |
13 | # Directory for instrumented libs generated by jscoverage/JSCover
14 | lib-cov
15 |
16 | # Coverage directory used by tools like istanbul
17 | coverage
18 |
19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
20 | .grunt
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # Commenting this out is preferred by some people, see
27 | # https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
28 | node_modules
29 |
30 | # Users Environment Variables
31 | .lock-wscript
32 |
33 | # vim swap files
34 | .*.sw?
35 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | node_js:
4 | - "6"
5 | - "7"
6 | - "8"
7 | before_install:
8 | - npm install -g npm@next
9 | notifications:
10 | hipchat:
11 | rooms:
12 | secure: wIUsb9E0kurkWR1DgtvkpfOYCsQqrIfPSWh5mnKV604MX9IHwYxCLDTdoFV+zs9jabV2wGA33WjE+he5X5yjYHhqfxVTU0q4R5VG8A1PJqpGwnXk/cYQIUD7m+oAV/CTCzG1ldj9aq9RdHPdClCIk4JInziNW5P30lV3Yeqq2z0=
13 | template:
14 | - '%{repository}
15 | Build %{build_number} on branch %{branch} by %{author}: %{message}
16 | View on GitHub'
17 | format: html
18 | notify: true
19 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | ## [0.2.0] - 2015-7-06
5 | ### Added
6 | - cc
7 | - bcc
8 | - api key support
9 | - replyTo
10 |
11 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # SendGrid Community Code of Conduct
2 |
3 | The SendGrid open source community is made up of members from around the globe with a diverse set of skills, personalities, and experiences. It is through these differences that our community experiences successes and continued growth. When you're working with members of the community, we encourage you to follow these guidelines, which help steer our interactions and strive to maintain a positive, successful and growing community.
4 |
5 | ## Table of Contents
6 | - [Code of Conduct](#code-of-conduct)
7 | - [Additional Guidance](#additional-guidance)
8 | - [Conduct Concerns](#conduct-concerns)
9 | - [Submission to SendGrid Repositories](#submission)
10 | - [Attribution](#attribution)
11 |
12 |
13 | ### Be Open
14 | Members of the community are open to collaboration, whether it's on pull requests, code reviews, approvals, issues or otherwise. We're receptive to constructive comments and criticism, as the experiences and skill sets of all members contribute to the whole of our efforts. We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate, and everyone can make a difference.
15 |
16 | ### Be Considerate
17 | Members of the community are considerate of their peers, which include other contributors and users of SendGrid. We're thoughtful when addressing the efforts of others, keeping in mind that often the labor was completed with the intent of the good of the community. We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views.
18 |
19 | ### Be Respectful
20 | Members of the community are respectful. We're respectful of others, their positions, their skills, their commitments and their efforts. We're respectful of the volunteer efforts that permeate the SendGrid community. We're respectful of the processes outlined in the community, and we work within them. When we disagree, we are courteous in raising our issues. Overall, we're good to each other. We contribute to this community not because we have to, but because we want to. If we remember that, these guidelines will come naturally.
21 |
22 |
23 | ## Additional Guidance
24 |
25 | ### Disclose Potential Conflicts of Interest
26 | Community discussions often involve interested parties. We expect participants to be aware when they are conflicted due to employment or other projects they are involved in and disclose those interests to other project members. When in doubt, over-disclose. Perceived conflicts of interest are important to address so that the community’s decisions are credible even when unpopular, difficult or favorable to the interests of one group over another.
27 |
28 | ### Interpretation
29 | This Code is not exhaustive or complete. It is not a rulebook; it serves to distill our common understanding of a collaborative, shared environment and goals. We expect it to be followed in spirit as much as in the letter. When in doubt, try to abide by [SendGrid’s cultural values](https://sendgrid.com/blog/employee-engagement-the-4h-way) defined by our “4H’s”: Happy, Hungry, Humble and Honest.
30 |
31 | ### Enforcement
32 | Most members of the SendGrid community always comply with this Code, not because of the existence of this Code, but because they have long experience participating in open source communities where the conduct described above is normal and expected. However, failure to observe this Code may be grounds for suspension, reporting the user for abuse or changing permissions for outside contributors.
33 |
34 |
35 | ## If you have concerns about someone’s conduct
36 | **Initiate Direct Contact** - It is always appropriate to email a community member (if contact information is available), mention that you think their behavior was out of line, and (if necessary) point them to this Code.
37 |
38 | **Discuss Publicly** - Discussing publicly is always acceptable. Note, though, that approaching the person directly may be better, as it tends to make them less defensive, and it respects the time of other community members, so you probably want to try direct contact first.
39 |
40 | **Contact the Moderators** - You can reach the SendGrid moderators by emailing dx@sendgrid.com.
41 |
42 |
43 | ## Submission to SendGrid Repositories
44 | Finally, just a reminder, changes to the SendGrid repositories will only be accepted upon completion of the [SendGrid Contributor Agreement](https://cla.sendgrid.com).
45 |
46 |
47 | ## Attribution
48 |
49 | SendGrid thanks the following, on which it draws for content and inspiration:
50 |
51 | * [Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/)
52 | * [Open Source Initiative General Code of Conduct](https://opensource.org/codeofconduct)
53 | * [Apache Code of Conduct](https://www.apache.org/foundation/policies/conduct.html)
54 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Hello! Thank you for choosing to help contribute to one of the SendGrid open source libraries. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies.
2 |
3 | - [CLAs and CCLAs](#clas-and-cclas)
4 | - [Roadmap & Milestones](#roadmap-and-milestones)
5 | - [Feature Request](#feature-request)
6 | - [Submit a Bug Report](#submit-a-bug-report)
7 | - [Improvements to the Codebase](#improvements-to-the-codebase)
8 | - [Understanding the Code Base](#understanding-the-codebase)
9 | - [Testing](#testing)
10 | - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions)
11 | - [Creating a Pull Request](#creating-a-pull-request)
12 |
13 |
14 | We use [Milestones](https://github.com/sendgrid/nodemailer-sendgrid-transport/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions and additional PRs are welcomed and encouraged.
15 |
16 |
17 | ## CLAs and CCLAs
18 |
19 | Before you get started, SendGrid requires that a SendGrid Contributor License Agreement (CLA) be filled out by every contributor to a SendGrid open source project.
20 |
21 | Our goal with the CLA is to clarify the rights of our contributors and reduce other risks arising from inappropriate contributions. The CLA also clarifies the rights SendGrid holds in each contribution and helps to avoid misunderstandings over what rights each contributor is required to grant to SendGrid when making a contribution. In this way the CLA encourages broad participation by our open source community and helps us build strong open source projects, free from any individual contributor withholding or revoking rights to any contribution.
22 |
23 | SendGrid does not merge a pull request made against a SendGrid open source project until that pull request is associated with a signed CLA. Copies of the CLA are available [here](https://gist.github.com/SendGridDX/98b42c0a5d500058357b80278fde3be8#file-sendgrid_cla).
24 |
25 | When you create a Pull Request, after a few seconds, a comment will appear with a link to the CLA. Click the link and fill out the brief form and then click the "I agree" button and you are all set. You will not be asked to re-sign the CLA unless we make a change.
26 |
27 | There are a few ways to contribute, which we'll enumerate below:
28 |
29 |
30 | ## Feature Request
31 |
32 | If you'd like to make a feature request, please read this section.
33 |
34 | The GitHub issue tracker is the preferred channel for library feature requests, but please respect the following restrictions:
35 |
36 | - Please **search for existing issues** in order to ensure we don't have duplicate bugs/feature requests.
37 | - Please be respectful and considerate of others when commenting on issues
38 |
39 |
40 | ## Submit a Bug Report
41 |
42 | Note: DO NOT include your credentials in ANY code examples, descriptions, or media you make public.
43 |
44 | A software bug is a demonstrable issue in the code base. In order for us to diagnose the issue and respond as quickly as possible, please add as much detail as possible into your bug report.
45 |
46 | Before you decide to create a new issue, please try the following:
47 |
48 | 1. Check the Github issues tab if the identified issue has already been reported, if so, please add a +1 to the existing post.
49 | 2. Update to the latest version of this code and check if issue has already been fixed
50 | 3. Copy and fill in the Bug Report Template we have provided below
51 |
52 | ### Please use our Bug Report Template
53 |
54 | In order to make the process easier, we've included a [sample bug report template](https://github.com/sendgrid/nodemailer-sendgrid-transport/.github/ISSUE_TEMPLATE) (borrowed from [Ghost](https://github.com/TryGhost/Ghost/)). The template uses [GitHub flavored markdown](https://help.github.com/articles/github-flavored-markdown/) for formatting.
55 |
56 |
57 | ## Improvements to the Codebase
58 |
59 | We welcome direct contributions to the nodemailer-sendgrid-transport code base. Thank you!
60 |
61 | ### Development Environment ###
62 |
63 | #### Install and Run Locally ####
64 |
65 | ##### Prerequisites #####
66 |
67 | - Node.js version 0.10, 0.12 or 4
68 | - Please see [package.json](https://github.com/sendgrid/nodemailer-sendgrid-transport/blob/master/package.json)
69 |
70 | ##### Initial setup: #####
71 |
72 | ```bash
73 | git clone https://github.com/sendgrid/nodemailer-sendgrid-transport.git
74 | cd nodemailer-sendgrid-transport
75 | npm install
76 | ```
77 |
78 | ##### Execute: #####
79 |
80 | See the [examples folder](https://github.com/sendgrid/nodemailer-sendgrid-transport/tree/master/examples) to get started quickly.
81 |
82 | You will need to setup the following environment to use the SendGrid example:
83 |
84 | ```bash
85 | echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env
86 | echo "sendgrid.env" >> .gitignore
87 | source ./sendgrid.env
88 | node examples/example.js
89 | ```
90 |
91 | To run the example:
92 |
93 | ```bash
94 | node ./examples/example.js
95 | ```
96 |
97 |
98 | ## Understanding the Code Base
99 |
100 | **/examples**
101 |
102 | Working examples that demonstrate usage.
103 |
104 | **client.js**
105 |
106 | There is an object to hold both the request and response to the API server.
107 |
108 | The main function that does the heavy lifting (and external entry point) is `API`.
109 |
110 |
111 | ## Testing
112 |
113 | All PRs require passing tests before the PR will be reviewed.
114 |
115 | All test files are in [`test/test.js`](https://github.com/sendgrid/nodemailer-sendgrid-transport/blob/master/test/test.js).
116 |
117 | For the purposes of contributing to this repo, please update the [`test.js`](https://github.com/sendgrid/nodemailer-sendgrid-transport/blob/master/test/test.js) file with unit tests as you modify the code.
118 |
119 | Run the test:
120 |
121 | `mocha`
122 |
123 |
124 | ## Style Guidelines & Naming Conventions
125 |
126 | Generally, we follow the style guidelines as suggested by the official language. However, we ask that you conform to the styles that already exist in the library. If you wish to deviate, please explain your reasoning.
127 |
128 | - [Unofficial Style Guide](https://github.com/felixge/node-style-guide)
129 |
130 | Please run your code through:
131 |
132 | - [ESLint](http://eslint.org/) with the standard style guide.
133 |
134 |
135 | ## Creating a Pull Request
136 |
137 | 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork,
138 | and configure the remotes:
139 |
140 | ```bash
141 | # Clone your fork of the repo into the current directory
142 | git clone https://github.com/sendgrid/nodemailer-sendgrid-transport
143 | # Navigate to the newly cloned directory
144 | cd nodemailer-sendgrid-transport
145 | # Assign the original repo to a remote called "upstream"
146 | git remote add upstream https://github.com/sendgrid/nodemailer-sendgrid-transport
147 | ```
148 |
149 | 2. If you cloned a while ago, get the latest changes from upstream:
150 |
151 | ```bash
152 | git checkout
153 | git pull upstream
154 | ```
155 |
156 | 3. Create a new topic branch (off the main project development branch) to
157 | contain your feature, change, or fix:
158 |
159 | ```bash
160 | git checkout -b
161 | ```
162 |
163 | 4. Commit your changes in logical chunks. Please adhere to these [git commit
164 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
165 | or your code is unlikely to be merged into the main project. Use Git's
166 | [interactive rebase](https://help.github.com/articles/interactive-rebase)
167 | feature to tidy up your commits before making them public.
168 |
169 | 4a. Create tests.
170 |
171 | 4b. Create or update the example code that demonstrates the functionality of this change to the code.
172 |
173 | 5. Locally merge (or rebase) the upstream development branch into your topic branch:
174 |
175 | ```bash
176 | git pull [--rebase] upstream master
177 | ```
178 |
179 | 6. Push your topic branch up to your fork:
180 |
181 | ```bash
182 | git push origin
183 | ```
184 |
185 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
186 | with a clear title and description against the `master` branch. All tests must be passing before we will review the PR.
187 |
188 | If you have any additional questions, please feel free to [email](mailto:dx@sendgrid.com) us or create an issue in this repo.
189 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016-2017 SendGrid
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 |
3 | [](https://travis-ci.org/sendgrid/nodemailer-sendgrid-transport)
4 | []()
5 | [](http://badge.fury.io/js/nodemailer-sendgrid-transport)
6 | [](https://twitter.com/sendgrid)
7 | [](https://github.com/sendgrid/nodemailer-sendgrid-transport/graphs/contributors)
8 |
9 | # Important Announcement
10 |
11 | **As of June 1, 2016, SendGrid will no longer support this library.**
12 |
13 | Please direct any questions to the [Developer Experience](mailto:dx@sendgrid.com) team.
14 |
15 | # nodemailer-sendgrid-transport
16 |
17 | This module is a transport plugin for [Nodemailer](https://github.com/andris9/Nodemailer) that makes it possible to send through [SendGrid's Web API](https://sendgrid.com/docs/API_Reference/Web_API/mail.html)!
18 |
19 | ## Table of Contents
20 | - [Usage](#usage)
21 | - [Deploying](#deploying)
22 | - [License](#license)
23 |
24 |
25 | ## Usage
26 | [Library Usage Documentation](USAGE.md)
27 |
28 |
29 | ## License
30 | [The MIT License (MIT)](LICENSE.txt)
31 |
--------------------------------------------------------------------------------
/USAGE.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 | Install via npm.
3 |
4 | npm install nodemailer-sendgrid-transport
5 |
6 | Require the module and initialize it with your SendGrid credentials.
7 |
8 | ```javascript
9 | var nodemailer = require('nodemailer');
10 | var sgTransport = require('nodemailer-sendgrid-transport');
11 |
12 | // api key https://sendgrid.com/docs/Classroom/Send/api_keys.html
13 | var options = {
14 | auth: {
15 | api_key: 'SENDGRID_APIKEY'
16 | }
17 | }
18 |
19 | // or
20 |
21 | // username + password
22 | var options = {
23 | auth: {
24 | api_user: 'SENDGRID_USERNAME',
25 | api_key: 'SENDGRID_PASSWORD'
26 | }
27 | }
28 |
29 | var mailer = nodemailer.createTransport(sgTransport(options));
30 | ```
31 |
32 | Note: We suggest storing your SendGrid username and password as enviroment variables.
33 |
34 | Create an email and send it off!
35 |
36 | ```javascript
37 | var email = {
38 | to: ['joe@foo.com', 'mike@bar.com'],
39 | from: 'roger@tacos.com',
40 | subject: 'Hi there',
41 | text: 'Awesome sauce',
42 | html: 'Awesome sauce'
43 | };
44 |
45 | mailer.sendMail(email, function(err, res) {
46 | if (err) {
47 | console.log(err)
48 | }
49 | console.log(res);
50 | });
51 | ```
52 |
53 |
54 | ## Deploying
55 |
56 | * Confirm tests pass
57 | * Bump the version in `README.md`, `package.json`, `test/sendgrid-transport-test.js`
58 | * Update `CHANGELOG.md`
59 | * Confirm tests pass
60 | * Commit `Version bump vX.X.X`
61 | * `npm publish`
62 | * Push changes to GitHub
63 | * Release tag on GitHub `vX.X.X`
--------------------------------------------------------------------------------
/examples/simple.js:
--------------------------------------------------------------------------------
1 | var nodemailer = require('nodemailer');
2 | var sgTransport = require('../src/sendgrid-transport.js');
3 |
4 | var options = {
5 | auth: {
6 | api_user: process.env['SENDGRID_USERNAME'],
7 | api_key: process.env['SENDGRID_PASSWORD']
8 | }
9 | }
10 |
11 | var mailer = nodemailer.createTransport(sgTransport(options));
12 |
13 | var email = {
14 | to: ['foo@example.com', 'bar@example.com'],
15 | from: 'baz@example.com',
16 | subject: 'Hi there',
17 | text: 'Awesome sauce',
18 | html: 'Awesome sauce',
19 | attachments: [
20 | {
21 | filename: 'test.txt',
22 | path: __dirname + '/test.txt'
23 | }
24 | ]
25 | };
26 |
27 | mailer.sendMail(email, function(err, res) {
28 | if (err) {
29 | console.log(err)
30 | }
31 | console.log(res);
32 | });
33 |
--------------------------------------------------------------------------------
/examples/test.txt:
--------------------------------------------------------------------------------
1 | Hello text
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nodemailer-sendgrid-transport",
3 | "version": "0.2.0",
4 | "description": "SendGrid transport for Nodemailer",
5 | "main": "src/sendgrid-transport.js",
6 | "scripts": {
7 | "test": "mocha"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git://github.com/sendgrid/nodemailer-sendgrid-transport.git"
12 | },
13 | "keywords": [
14 | "Nodemailer",
15 | "SendGrid"
16 | ],
17 | "author": "SendGrid (sendgrid.com)",
18 | "contributors": [
19 | "Eddie Zaneski "
21 | ],
22 | "license": "MIT",
23 | "dependencies": {
24 | "sendgrid": "^1.8.0"
25 | },
26 | "devDependencies": {
27 | "chai": "^1.9.1",
28 | "mocha": "^1.20.1"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/sendgrid-transport.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var SendGrid = require('sendgrid');
4 | var packageData = require('../package.json');
5 |
6 | module.exports = function(options) {
7 | return new SendGridTransport(options);
8 | };
9 |
10 | function SendGridTransport(options) {
11 | options = options || {};
12 |
13 | this.options = options;
14 | this.name = 'SendGrid';
15 | this.version = packageData.version;
16 |
17 | if (!this.options.auth.api_user) {
18 | // api key
19 | this.sendgrid = SendGrid(this.options.auth.api_key);
20 | } else {
21 | // username + password
22 | this.sendgrid = SendGrid(this.options.auth.api_user, this.options.auth.api_key);
23 | }
24 | }
25 |
26 | // if in "name" format, reformat to just address@example.com
27 | function trimReplyTo(a) {
28 | if (a.indexOf('<') >= 0 && a.indexOf('>') > 0) {
29 | return a.substring(a.indexOf('<')+1, a.indexOf('>'));
30 | }
31 | return a;
32 | }
33 |
34 | SendGridTransport.prototype.send = function(mail, callback) {
35 | var email = mail.data;
36 |
37 | // reformat replyTo to replyto
38 | if (email.replyTo) {
39 | email.replyto = trimReplyTo(email.replyTo);
40 | }
41 |
42 | // fetch envelope data from the message object
43 | var addresses = mail.message.getAddresses();
44 | var from = [].concat(addresses.from || addresses.sender || addresses['reply-to'] || []).shift();
45 | var to = [].concat(addresses.to || []);
46 | var cc = [].concat(addresses.cc || []);
47 | var bcc = [].concat(addresses.bcc || []);
48 |
49 | // populate from and fromname
50 | if (from) {
51 | if (from.address) {
52 | email.from = from.address;
53 | }
54 |
55 | if (from.name) {
56 | email.fromname = from.name;
57 | }
58 | }
59 |
60 | // populate to and toname arrays
61 | email.to = to.map(function(rcpt) {
62 | return rcpt.address || '';
63 | });
64 |
65 | email.toname = to.map(function(rcpt) {
66 | return rcpt.name || '';
67 | });
68 |
69 | // populate cc and bcc arrays
70 | email.cc = cc.map(function(rcpt) {
71 | return rcpt.address || '';
72 | });
73 |
74 | email.bcc = bcc.map(function(rcpt) {
75 | return rcpt.address || '';
76 | });
77 |
78 | // a list for processing attachments
79 | var contents = [];
80 |
81 | // email.text could be a stream or a file, so store it for processing
82 | if (email.text) {
83 | contents.push({
84 | obj: email,
85 | key: 'text'
86 | });
87 | }
88 |
89 | // email.html could be a stream or a file, so store it for processing
90 | if (email.html) {
91 | contents.push({
92 | obj: email,
93 | key: 'html'
94 | });
95 | }
96 |
97 | // store attachments for processing, to fetch files, urls and streams
98 | email.files = email.attachments;
99 | [].concat(email.files || []).forEach(function(attachment, i) {
100 | contents.push({
101 | obj: email.files,
102 | key: i,
103 | isAttachment: true
104 | });
105 | });
106 |
107 | // fetch values for text/html/attachments as strings or buffers
108 | // this is an asynchronous action, so we'll handle it with a simple recursion
109 | var _self = this;
110 | var pos = 0;
111 | var resolveContent = function() {
112 |
113 | // if all parts are processed, send out the e-mail
114 | if (pos >= contents.length) {
115 | return _self.sendgrid.send(email, function(err, json) {
116 | callback(err, json);
117 | });
118 | }
119 |
120 | // get the next element from the processing list
121 | var file = contents[pos++];
122 | /*
123 | We need to store a pointer to the original attachment object in case
124 | resolveContent replaces it with the Stream value
125 | */
126 | var prevObj = file.obj[file.key];
127 | // ensure the object is an actual attachment object, not a string, buffer or a stream
128 | if (prevObj instanceof Buffer || typeof prevObj === 'string' || (prevObj && typeof prevObj.pipe === 'function')) {
129 | prevObj = {
130 | content: prevObj
131 | };
132 | }
133 |
134 | // use the helper function to convert file paths, urls and streams to strings or buffers
135 | mail.resolveContent(file.obj, file.key, function(err, content) {
136 | if (err) {
137 | return callback(err);
138 | }
139 |
140 | if (!file.isAttachment) {
141 | // overwrites email.text and email.html content
142 | file.obj[file.key] = content;
143 | } else {
144 |
145 | // If the object is a String or a Buffer then it is most likely replaces by resolveContent
146 | if (file.obj[file.key] instanceof Buffer || typeof file.obj[file.key] === 'string') {
147 | file.obj[file.key] = prevObj;
148 | }
149 | file.obj[file.key].content = content;
150 | if (file.obj[file.key].path) {
151 | if (!file.obj[file.key].filename) {
152 | // try to detect the required filename from the path
153 | file.obj[file.key].filename = file.obj[file.key].path.split(/[\\\/]/).pop();
154 | }
155 | delete file.obj[file.key].path;
156 | }
157 | // set default filename if filename and content-type are not set (allowed for Nodemailer but not for SendGrid)
158 | if (!file.obj[file.key].filename && !file.obj[file.key].contentType) {
159 | file.obj[file.key].filename = 'attachment-' + pos + '.bin';
160 | }
161 | }
162 |
163 | resolveContent();
164 | });
165 | };
166 |
167 | // start the recursive function
168 | resolveContent();
169 | };
170 |
--------------------------------------------------------------------------------
/test/license-test.js:
--------------------------------------------------------------------------------
1 | var expect = require('chai').expect;
2 | var assert = require('assert');
3 | var fs = require('fs');
4 |
5 | describe('LICENSE', function() {
6 | it('should have correct end year', function(done) {
7 | var licenseFile = fs.readFileSync('LICENSE.txt', 'utf8');
8 | var yearRange = licenseFile.split('\n')[2].split(' ')[2];
9 | var endYear = parseInt(yearRange.split('-')[1]);
10 | var currentYear = (new Date()).getFullYear();
11 |
12 | if (endYear !== currentYear) {
13 | expect(endYear).to.eq(currentYear);
14 | } else {
15 | done();
16 | }
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/test/sendgrid-transport-test.js:
--------------------------------------------------------------------------------
1 | var sgTransport = require('../src/sendgrid-transport.js');
2 | var expect = require('chai').expect;
3 |
4 | var pkg = require('../package.json');
5 |
6 | var transport = null;
7 |
8 | describe('sendgrid-transport', function() {
9 | it('should take an api_user and api_key', function() {
10 | transport = sgTransport({ 'auth': { api_user: 'test', api_key: 'test' } })
11 | });
12 |
13 | it('should take an apikey', function() {
14 | transport = sgTransport({ 'auth': { api_key: 'test' } })
15 | });
16 |
17 | it('should have a name and version', function() {
18 | expect(transport.name).to.eq('SendGrid')
19 | expect(transport.version).to.eq(pkg.version)
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var fs = require('fs');
3 |
4 | describe('nodemailer-sendgrid-transport repo', function() {
5 | it('should have ./Dockerfile or docker/Dockerfile', function() {
6 | assert(fileExists('Dockerfile') || fileExists('docker/Dockerfile'));
7 | });
8 |
9 | it('should have ./docker-compose.yml or ./docker/docker-compose.yml file', function() {
10 | assert(fileExists('docker-compose.yml') || fileExists('docker/docker-compose.yml'));
11 | });
12 |
13 | it('should have ./.env_sample file', function() {
14 | assert(fileExists('.env_sample'));
15 | });
16 |
17 | it('should have ./.gitignore file', function() {
18 | assert(fileExists('.gitignore'));
19 | });
20 |
21 | it('should have ./.travis.yml file', function() {
22 | assert(fileExists('.travis.yml'));
23 | });
24 |
25 | it('should have ./.codeclimate.yml file', function() {
26 | assert(fileExists('.codeclimate.yml'));
27 | });
28 |
29 | it('should have ./CHANGELOG.md file', function() {
30 | assert(fileExists('CHANGELOG.md'));
31 | });
32 |
33 | it('should have ./CODE_OF_CONDUCT.md file', function() {
34 | assert(fileExists('CODE_OF_CONDUCT.md'));
35 | });
36 |
37 | it('should have ./CONTRIBUTING.md file', function() {
38 | assert(fileExists('CONTRIBUTING.md'));
39 | });
40 |
41 | it('should have ./.github/ISSUE_TEMPLATE file', function() {
42 | assert(fileExists('.github/ISSUE_TEMPLATE'));
43 | });
44 |
45 | it('should have ./LICENSE.md file', function() {
46 | assert(fileExists('LICENSE.md') || fileExists('LICENSE.txt'));
47 | });
48 |
49 | it('should have ./.github/PULL_REQUEST_TEMPLATE file', function() {
50 | assert(fileExists('.github/PULL_REQUEST_TEMPLATE'));
51 | });
52 |
53 | it('should have ./README.md file', function() {
54 | assert(fileExists('README.md'));
55 | });
56 |
57 | it('should have ./TROUBLESHOOTING.md file', function() {
58 | assert(fileExists('TROUBLESHOOTING.md'));
59 | });
60 |
61 | it('should have ./USAGE.md file', function() {
62 | assert(fileExists('USAGE.md'));
63 | });
64 |
65 | it('should have ./USE_CASES.md file', function() {
66 | assert(fileExists('USE_CASES.md'));
67 | });
68 |
69 | function fileExists(filepath) {
70 | try {
71 | return fs.statSync(filepath).isFile();
72 | } catch(e) {
73 | if (e.code === 'ENOENT') {
74 | console.log('' + filepath + ' doesn\'t exist.');
75 | return false;
76 | }
77 | throw e;
78 | }
79 | }
80 | });
81 |
--------------------------------------------------------------------------------