Resend Mailer not working

Hello!

I implemented a mailer (Mailer | RedwoodJS Docs) using the docs, and emails are sending fine in dev environment (I can see them coming in on Redwood Studio). However, the Resend implementation doesn’t seem to be working.

This is my mailer implementation:

import { Mailer } from '@redwoodjs/mailer-core'
import { NodemailerMailHandler } from '@redwoodjs/mailer-handler-nodemailer'
import { ResendMailHandler } from '@redwoodjs/mailer-handler-resend'
import { ReactEmailRenderer } from '@redwoodjs/mailer-renderer-react-email'

import { logger } from 'src/lib/logger'

export const mailer = new Mailer({
  handling: {
    handlers: {
      nodemailer: new NodemailerMailHandler({
        transport: {
          host: 'localhost',
          port: 4319,
          secure: false,
        },
      }),
      resend: new ResendMailHandler({
        apiKey: process.env.RESEND_API_KEY,
      }),
    },
    default: 'resend',
  },

  rendering: {
    renderers: {
      reactEmail: new ReactEmailRenderer(),
    },
    default: 'reactEmail',
  },

  logger,
})

And this is my resolver:

import { mailer } from 'src/lib/mailer'


export const createEarlyAccessUser: MutationResolvers['createEarlyAccessUser'] =
  async ({ input }) => {
    const user = await db.earlyAccessUser.create({
      data: input,
    })

    // Send email
    await mailer.send(
      OnTheListEmail({
        userId: user.id,
      }),
      {
        to: user.email,
        subject: "You're on the list",
        from: 'noreply@domain.com',
      }
    )
    console.log(`Confirmation email has been sent to ${user.email}`)

    return user
  }

Can’t figure out what I’m doing wrong, and was wondering if anyone could help? Thank you!

Hi @charliem somewhat good timing as I had planned this week to rework the Resend docs and their example app to use Mailer.

As part of it, I’ll verify the Redwood docs and setup as well.

One question: how / where were you sending to Resend? Did you expect to see mails be sent to both Studio and Resend in development? If so, that’s not the expected behavior.

You can control the development mode behavior with the following configuration in the mailer.ts

And then y it can tell development to send using the Resend handler:

development:%20%7B%0A%20%20when%3A%20process.env.NODE_ENV%20!==%20’production’,%0A%20%20handler%3A%20’someOtherHandler’,%0A%7D,

Thanks @dthyresson, I love it when good timing happens :).

In terms of expected behavior - yes, I was expecting the mailer to fire emails through all handlers. It wasn’t clear from the documentation that this shouldn’t be the expected behavior, so that probably needs a bit of updating.

I added the development mode but that didn’t do anything regarding resend, btw. Even when I push to production (using vercel), it seems the mailer is still trying to use the nodemailer. I’ve even manually set NODE_ENV to production on vercel (even though I think vercel sets this automatically), to no avail.

Idea: in the same way you have the development config, we should also have a production config. That’ll make things a bit more clear, IMO.

LMK whether you have any other ideas on how to investigate why resend isn’t working, even in prod. Thank you!

@charliem I got started earlier on an update to the Redwood + Resend Example app here: GitHub - redwoodjs/resend-redwoodjs-example at dt-redwood-mailer

Typically, I prefer to use Redwood Mailer in dev to send to Studio (to prevent live mail leaking out in wild … and to design my email templates) and then deploy and use Resend.

That said, can see here that I am forcing it always to send with the resend handler here:

As I work on this example app I’ll be updating as I learn the best pattern sand then also revise the docs to be more helpful – or PRs for docs are super welcome and much appreciated.

The docs live here: https://github.com/redwoodjs/redwood/blob/main/docs/docs/mailer.md

Thanks for trying out mailer – the Studio integration is really great.

Just do: yarn rw experimental studio

FYI in v7 rc we’ll have more Studio updates.

Thanks @dthyresson. Forcing development to ‘resend’ is a great idea for testing to make sure everything would work well in prod. Just tried that and it worked - thank you.

I think I can help make the docs a bit better, will try to do a PR over the weekend.

As always, appreciate your help!

1 Like

That would be super!

BTW, not documented enough but you can do something like:

const getHandler = () => {
  if (process.env.RESEND_API_KEY) {
    return 'resend'
  }

  return 'nodemailer'
}

export const mailer = new Mailer({
  // development: {
  //   when: process.env.NODE_ENV !== 'production',
  //   handler: 'resend',
  // },
  development: {
    handler: getHandler(),
  },

So, you could define “some function” that can check what handler to use in development. So, could have some way to override the safety net of Studio handling in dev if you really need to.

But, you do have control over those config settings. for handler and when.

1 Like

That’s exactly what I needed, thank you @dthyresson!