Skip to content

Brevo transporter using v3 API (latest) not working #105

@arthur-pigeon

Description

@arthur-pigeon

Package version

9.2.2

Describe the bug

I am using the Brevo transporter to deliver mail, and using the current latest v3 API version of Brevo, sending emails with a replyTo option doesn't work and returns a 400 status code (from Brevo api call).

Here is my mail.ts config file:

import env from '#start/env'
import { defineConfig, transports } from '@adonisjs/mail'

const mailConfig = defineConfig({
  default: 'brevo',

  from: {
    address: env.get('BREVO_FROM_EMAIL'),
    name: env.get('BREVO_FROM_NAME'),
  },

  replyTo: {
    address: env.get('BREVO_FROM_EMAIL'),
    name: env.get('BREVO_FROM_NAME'),
  },

  mailers: {
    brevo: transports.brevo({
      key: env.get('BREVO_API_KEY'),
      baseUrl: 'https://api.brevo.com/v3',
    }),
  },
})

export default mailConfig

declare module '@adonisjs/mail/types' {
  export interface MailersList extends InferMailers<typeof mailConfig> {}
}

API key is working, as well as all other options because I can send emails with the exact same setup with a curl command like this (envs are hardcoded in the string):

curl --request POST \
     --url https://api.brevo.com/v3/smtp/email \
     --header 'accept: application/json' \
     --header 'api-key: $BREVO_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "sender": {
    "name": "$BREVO_FROM_NAME",
    "email": "$BREVO_FROM_EMAIL"
  },
  "to": [
    {
      "email": "test@mail.com",
      "name": "John"
    }
  ],
  "htmlContent": "<!DOCTYPE html> <html> <body> <h1>Confirm you email</h1> <p>Please confirm your email address by clicking on the link below</p> </body> </html>",
  "textContent": "Please confirm your email address by clicking on the link https://domain.com",
  "subject": "Login Email confirmation",
  "replyTo": {
    "email": "$BREVO_FROM_EMAIL",
    "name": "$BREVO_FROM_NAME"
  }
}
'

After investigation, the Brevo documentation for sending emails mention that the replyTo field must me an object containing email and name fields. But the when crafting the payload here:

async send(mail: MailMessage, callback: (err: Error | null, info: BrevoSentMessageInfo) => void) {
const url = `${this.#getBaseUrl()}/smtp/email`
const envelope = mail.message.getEnvelope()
const payload = this.#preparePayload(mail)

Then here:

if (mail.data.replyTo) {
payload.replyTo = this.#formatAddresses(mail.data.replyTo)
}

And finally here:

#formatAddresses(rawAddresses: string | Address | Array<string | Address> | undefined) {
const addresses = Array.isArray(rawAddresses) ? rawAddresses : [rawAddresses]
return addresses.map((address) => this.#formatAddress(address))
}

The #preparePayload function that calls the #formatAddresses to prepare the replyTo field create an array of replyTo objects instead of just one.
And I believe this is what lead the requests to fail

Reproduction repo

Private

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions