Skip to content

Commit

Permalink
allow filtering of emails in http endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
madflow committed Apr 1, 2021
1 parent 96248f8 commit 0818319
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 3 deletions.
12 changes: 11 additions & 1 deletion docs/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,19 @@ Returns:

**GET /email/:id/attachment/:filename** - Get a given email's file attachment.

**POST /email/:id/relay** - If configured, relay a given email to it's real
**POST /email/:id/relay** - If configured, relay a given email to it's real
"to" address.

**GET /config** - Get the application configuration.

**GET /healthz** - Health check

## Filtering

The **GET /email** endpoint does allow simple filtering. Every field content of the returned payload can be used to only return desired emails. Nested objects can be defined by using a dot syntax (`headers.to=value`).

For example:

```GET email?subject="Big wave coming" # only emails with the exact subject```

```GET email?headers.some-header="some-value"&subject=test # only emails with the exact subject and header value```
9 changes: 7 additions & 2 deletions lib/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
const express = require('express')
const pkg = require('../package.json')
const { filterEmails } = require('./utils')

const emailRegexp = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

Expand All @@ -15,8 +16,12 @@ module.exports = function (app, mailserver, basePathname) {
router.get('/email', function (req, res) {
mailserver.getAllEmail(function (err, emailList) {
if (err) return res.status(404).json([])

res.json(emailList)
if (req.query) {
const filteredEmails = filterEmails(emailList, req.query)
res.json(filteredEmails)
} else {
res.json(emailList)
}
})
})

Expand Down
35 changes: 35 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,38 @@ utils.formatBytes = function (bytes, decimals = 2) {
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
}

function lookup (obj, path) {
const parts = path.split('.')
const base = obj[parts[0]]
if (!base) return
if (parts.length === 1) {
return base
}
const next = parts.slice(1).join('.')
if (Array.isArray(base)) {
return base.map((el) => {
return lookup(el, next)
})
} else {
return lookup(base, next)
}
}

utils.filterEmails = function (emails, query) {
return emails.filter((email) => {
const hits = []
for (const key in query) {
if (Object.hasOwnProperty.call(query, key)) {
const element = query[key]
const value = lookup(email, key)
if (Array.isArray(value)) {
hits.push(value.includes(element))
} else {
hits.push(value === element)
}
}
}
return !hits.includes(false)
})
}
27 changes: 27 additions & 0 deletions test/middleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,31 @@ describe('middleware', function () {
.catch(done)
})
})

it('should allow filtering', function (done) {
const transporter = nodemailer.createTransport(defaultNodemailerOpts)

const emailOpts = {
from: 'johnny.utah@fbi.gov',
to: 'bodhi@gmail.com',
subject: 'Test',
html: 'Test'
}

transporter.sendMail(emailOpts)

maildev.on('new', function () {
got('http://localhost:8080/maildev/email?subject=Test&to.address=bodhi@gmail.com')
.then(function (res) {
assert.strictEqual(res.statusCode, 200)

const json = JSON.parse(res.body)
assert(json.length === 1)
assert(json[0].subject === 'Test')

done()
})
.catch(done)
})
})
})
16 changes: 16 additions & 0 deletions test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,20 @@ describe('utils', () => {
expect(utils.makeId()).toMatch(alphaNumericRegex)
})
})

describe('filterEmails', () => {
const emails = [
{ subject: 'Test', headers: { 'x-some-header': 1 } },
{ subject: 'Test' },
{ subject: 'Test2' }
]

it('should filter by differect predicates', () => {
expect(utils.filterEmails(emails, { subject: 'Test' }).length).toEqual(2)
expect(utils.filterEmails(emails, { subject: 'Test2' }).length).toEqual(1)
expect(utils.filterEmails(emails, { 'headers.x-some-header': 1 }).length).toEqual(1)
expect(utils.filterEmails(emails, { subject: 'Test', 'headers.x-some-header': 1 }).length).toEqual(1)
expect(utils.filterEmails(emails, { subject: 'Test', 'headers.x-some-header': 0 }).length).toEqual(0)
})
})
})

0 comments on commit 0818319

Please sign in to comment.