Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/charlesread/sneakemail
https://github.com/charlesread/sneakemail
Last synced: 21 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/charlesread/sneakemail
- Owner: charlesread
- Created: 2017-02-11T13:41:53.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2017-02-13T01:45:09.000Z (over 7 years ago)
- Last Synced: 2024-10-05T05:01:15.569Z (about 1 month ago)
- Language: HTML
- Size: 1.37 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Sneakemail
Ever wonder how companies like _Constant Contact_ or _MailChimp_ track when somebody opens one of their emails? It's pretty neat, and _Sneakemail_ effectively recreates it, although probably in a less robust way.
Nevertheless, _Sneakemail_ will allow you to send emails and know when those emails have been opened.
## Moving Parts
_Sneakemail_ consists of an **API** and a [soon to come] **UI**.
### API
The API uses _Hapi_, to handle the endpoints, and _nodemailer_, to send emails. During configuration you have direct access to both of these modules, so you can manipulate them however you lke.
By default, the _Sneakemail_ API will create the two endpoints:
#### `/email [POST]`
This endpoint cab be used to send an email, and inject into that email the sneaky bit: that which allows you to track when an email has been opened. You, or your application, make an HTTP POST to this endpoint with a body like the following:```json
{
"to":"[email protected]",
"fromName": "Frank Foo",
"subject": "Super Important Meeting",
"html": "blah blah bar
",
"passthrough": {
"username": "ffoo",
"emailId": 1234567
}
}
```The _Sneakemail_ API will then send an email to `to` and appends a `` tag to the `html`. The `href` attribute of the `` tag will be a URL that that is seemingly the location of a CSS file. But it's not a real CSS file, before the _Sneakemail_ API sends the email it encrypts the `passthrough` object that was posted to `/email` and that encrypted string becomes the name of the CSS file referenced in the ``'s `href` attribute (the name of the CSS file becomes the `slug` in the endpoint below.
#### `/{slug}.css [GET]`This is how the tracking works. When an email client downloads the CSS file in the body of the email this endpoint decrypts the encrypted `slug` (name of the CSS file), and now has complete access to the `passthrough` object that was POSTed to `/email`.
### UI
More info on the UI to come, it's pretty much done, and all it really does is just put a pretty face on posting to the API. Check out the working example below.
### Usage
Install `sneakemail`
```
npm install --save sneakemail
```Check out `config/config.js` for the default configuration. The options given to `api.init()` and `ui.init()` are merged with the defaults, at minimum your options should contain the `transporter` and `sneakemail.fromAddress` attributes (because that's specific to you).
```javascript
'use strict'const path = require('path')
const co = require('bluebird-co').coconst Sneakemail = require('sneakemail')
const api = Sneakemail.api
const ui = Sneakemail.uiconst options = {
// the api object gets passed DIRECTLY to the Hapi `server.connection()` method
server: {
api: {
port: 3000
}
},
// these values need to be entered accodeing to `node-mailer`: https://nodemailer.com/smtp/well-known,
// this object is passed DIRECTLY to nodemailer.createTransport(), so do whatever you like according to what
// `node-mailer` does, you, of course, don't have to use a "well-known" service, as this example does
transporter: {
service: 'Mailjet',
auth: {
user: '',
pass: ''
}
},
// this becomes the from address in the email that is sent
sneakemail: {
fromAddress: '[email protected]',
endpoints: {
api: {
emailPost: '/email' //default
},
ui: {
index: '/', //default
emailPost: '/email' //default
}
}
},
// this is the function that gets called when somebody opens an email, its argument is an object that contains the
// `to`, `subject`, and `passthrough` objects that were contained in the body of the HTTP POST to `/email`
openCallback: function (obj) {
console.log(obj)
}
}co(function *() {
yield api.init(options)
yield ui.init(options)// add some more routes if you so desire
api.server.route({
method: 'get',
path: '/',
handler: (req, reply) => {
reply('Welcome to the Sneakemail API')
}
})yield api.start()
yield ui.start()})
.then(() => {
console.log('api started at ', api.server.info.uri)
console.log('ui started at ', ui.server.info.uri)
// lets look at the route table just to confirm that our routes are regisred
console.log('api routes:')
api.server.table()[0].table.map((t) => {
console.log(' route %s [%s] is registered: %s%s', t.path, t.method, api.server.info.uri, t.path)
})
console.log('ui routes:')
ui.server.table()[0].table.map((t) => {
console.log(' route %s [%s] is registered: %s%s', t.path, t.method, ui.server.info.uri, t.path)
})
})
.catch(console.error)
```Will output something like
```
api started at http://10.0.0.167:3000
ui started at http://10.0.0.167:8080
api routes:
route /email [post] is registered: http://10.0.0.167:3000/email
route /{slug}.css [get] is registered: http://10.0.0.167:3000/{slug}.css
route / [get] is registered: http://10.0.0.167:3000/
ui routes:
route / [get] is registered: http://10.0.0.167:8080/
route /{param*} [get] is registered: http://10.0.0.167:8080/{param*}
route /static/{param*} [get] is registered: http://10.0.0.167:8080/static/{param*}
route /email [post] is registered: http://10.0.0.167:8080/email
```Now make a POST to `/email`, wait for the email to come, open it, and check your console!
Or browse to the `/` `ui` endpoint `http://10.0.0.167:8080/`.