This module will help you build an imap bot reacting to incoming emails.
You mainly provide two functions:
- A trigger which will be called for each received e-mail and should return a promise of a truthy if mail should trigger some job
- A mailHandler which will be called for each triggered e-mail and will do its job
There are actually no test because I found a bit too time-consuming to mock an Imap server for testing. They will come later.
npm install --save mailbot
const { createBot } = require('mailbot')
const bot = createBot(options)
bot.start()
// Start watching, returns a Promise
bot.start()
// Stops watching, returns a Promise
// if argument is true, it will destroy the connection immediately
// you're strongly advised to gracefully disconnect by not setting this parameter
bot.stop(destroy = false)
// Restarts
bot.restart(destroy = false)
// Update configuration option
// Note: if you update 'imap', 'mailbox', or 'filter', it will restart the bot
// unless said otherwise
bot.configure('imap', connectionInfo, autoRestart = true, destroy = false)
{
// IMAP configuration, see module "imap"
imap: {
user: "[email protected]",
password: "password",
host: "imap.googlemail.com",
port: 993,
keepalive: true,
tls: true,
tlsOptions: {
rejectUnauthorized: false
},
},
// Watched inbox
mailbox: 'INBOX',
// Should bot mark fetched emails as read?
// If true, you're sure you will never fetch same mail twice even when restarting
// If false, you'll mess with server emails
markSeen: true,
// Search filter to fetch emails
filter: ['UNSEEN'],
// Should the trigger be checked when receiving headers, or when body has been parsed?
// If your control depends only on headers (subject, recipient, sender…), you can set it to true
// Warning: in 'headers' phase, headers are not parsed yet and you may need helpers
triggerOnHeaders: false,
// The trigger: this function is called for each e-mail
// Input: a mail object (if triggerOnHeaders is true, it will only have 'headers' property)
// Output: a value or a promise of a value
// The mail will be "handled" only if final value is truthy
trigger ({ headers }) {
// Example: work with e-mails whose subject is 'BOT: <something>'
const match = headers.subject.match(/BOT: (.*)$/)
return match && match[1]
},
// The mail handler: this is the "job executor"
// Input: a mail object, and the trigger value
mailHandler (mail, trigger) {
console.log({
subject: mail.headers.subject,
trigger
})
},
// The error handler, called for each error occurring during processes
// As there may be error thrown from very different places,
// the function is called with a "context", which can be one of:
// - 'IMAP_ERROR': global error
// - 'SEARCH': failed searching or fetching mails
// - 'TRIGGER': when trying to calculate trigger result (*)
// - 'MAIL': when trying to handle mail (*)
// (*) in those cases the third parameter will be a complete mail object
// allowing you to access sender, subject, etc…
errorHandler (error, context, mail) {
console.error(context, error)
if (mail) {
sendErrorMailTo(mail.from)
}
},
// IMAP client reconnection
autoReconnect: true,
autoReconnectTimeout: 5000,
// false: attachments contents will be directly accessible as Buffer in 'content' property
// true: attachments will be streamed via 'stream' property
// Note: you can safely set it to false if you use triggerOnHeaders, otherwise you should work with streams
streamAttachments: true,
// If true, mail.text will not contain signature
// Properties 'textSignature' and 'textOriginal' will be added
removeTextSignature: true,
// If true, if embedded images are found in signature of mail.html
// they will be dropped from 'attachments' and moved to 'ignoredAttachments'
ignoreAttachmentsInSignature: true,
// If true, property 'cleanSubject' will contain the subject without all messy prefixes
cleanSubject: true,
// Set to a strictly positive number to define period (milliseconds) between automatic search
// Note that this delay starts AFTER a batch has been handled
// Any falsey value will disable periodic search
searchPeriod: false,
}
Mail objects are generated by mailparser
(version 0.x, not the buggy 2.0): see full description of parsed mail object.
Following custom properties are added:
- ignoredAttachments
- textSignature
- textOriginal
- cleanSubject
Working with triggerOnHeaders: true
is interesting for performance purpose, but you get unparsed headers. This function will help you working with to/cc/bcc
headers:
{
triggerOnHeaders: true,
trigger: ({ headers }) => {
console.log(headers.to) // "Bob" <[email protected]>
parseAddresses(headers)
console.log(headers.to) // [ { address: '[email protected]', raw: '"Bob" <[email protected]>', phrase: '"Bob"' } ]
}
}
This function will help you remove signature from e-mail body, using talon
:
const { text, signature } = extractSignature(mail.text)
This function will remove any HTML tag from a string, using striptags
internally:
const text = stripTags(mail.html)
This module uses debug
internally, and you can enable internal debug messages adding mailbot
to your environment variable DEBUG
:
env DEBUG=mailbot node mybot.js
See sample.js
in repository: it's a mail bot which will react on every mail which subject starts with 'upload to …'. It will fetch all attachments and save it to <upload dir>/<sender address>/<requested path>
.
This illustrates how you can easily create that type of bot.