node.jsconfigaws-sdkamazon-sesnode-config

TypeError: Key must be a buffer when sending an email with aws-sdk in node.js


I'm trying to set up an emailing system with nodemailer that's agnostic of the transport type it uses.

Here's how I'm trying to send the email:

const config = require('config')
const mailerConfig = config.get('mailer')
const transporter = nodemailer.createTransport(mailerConfig.transport)
transporter.sendMail({
  from: mailerConfig.from,
  to: toEmail,
  subject,
  text: textBody,
  html: htmlBody,
})

And here's how my config file looks like:

const AWS = require('aws-sdk')
module.exports = {
  mailer: {
    from: 'test_sender@domain.com',
    transport: {
      SES: new AWS.SES({
        accessKeyId: 'secret-key',
        secretAccessKey: 'access-key',
        region: 'region',
      }),
    },
  }
}

Then, whenever I try to send an email, I get the following error:

error:  TypeError: Key must be a buffer
    at new Hmac (crypto.js:117:16)
    at Object.Hmac (crypto.js:115:12)
    at Object.hmac (/Users/sebi/Work/node_modules/aws-sdk/lib/util.js:401:30)
    at Object.getSigningKey (/Users/sebi/Work/node_modules/aws-sdk/lib/signers/v4_credentials.js:59:8)
at V4.signature (/Users/sebi/Work/node_modules/aws-sdk/lib/signers/v4.js:97:36)
at V4.authorization (/Users/sebi/Work/node_modules/aws-sdk/lib/signers/v4.js:92:36)
at V4.addAuthorization (/Users/sebi/Work/node_modules/aws-sdk/lib/signers/v4.js:34:12)
at /Users/sebi/Work/node_modules/aws-sdk/lib/event_listeners.js:215:18
at finish (/Users/sebi/Work/node_modules/aws-sdk/lib/config.js:320:7)
at /Users/sebi/Work/node_modules/aws-sdk/lib/config.js:338:9
at /Users/sebi/Work/node_modules/aws-sdk/lib/credentials.js:123:23
at Credentials.refresh (/Users/sebi/Work/node_modules/aws-sdk/lib/credentials.js:194:5)
at Credentials.get (/Users/sebi/Work/node_modules/aws-sdk/lib/credentials.js:121:12)
at getAsyncCredentials (/Users/sebi/Work/node_modules/aws-sdk/lib/config.js:332:24)
at Config.getCredentials (/Users/sebi/Work/node_modules/aws-sdk/lib/config.js:352:9)
at Request.SIGN (/Users/sebi/Work/node_modules/aws-sdk/lib/event_listeners.js:192:22)

Please note that when I'm instantiating AWS.SES() in the same place where I'm sending the email, the code works fine. Is there anything special that config does to break the code?


Solution

  • Is there anything special that config does to break the code?

    Exactly. config package deep-merges all configs. So it walks thru your config, and breaks object returned from AWS.SES(). You can try to put your keys in config, and apply them to ses only on usage:

    const AWS = require('aws-sdk')
    module.exports = {
      mailer: {
        from: 'test_sender@domain.com',
        transport: {
          SES: {
            accessKeyId: 'secret-key',
            secretAccessKey: 'access-key',
            region: 'region',
          },
        },
      }
    }
    

    And use it:

    const config = require('config')
    const mailerConfig = config.get('mailer')
    const transporter = nodemailer.createTransport({
        SES: new AWS.SES(mailerConfig.transport.SES)
    })
    transporter.sendMail({
      from: mailerConfig.from,
      to: toEmail,
      subject,
      text: textBody,
      html: htmlBody,
    })
    

    As alternative you can require your config file directly:

    const config = require('./config') // depends on your files structure