Skip to main content

Command Palette

Search for a command to run...

✉️ Designing Your Own Mail Driver with AdonisJS 5

Published
3 min read
✉️ Designing Your Own Mail Driver with AdonisJS 5
S

🔧 Professional/Polished: Full Stack Developer | AdonisJS, Vue.js, AWS | Building scalable web apps. Writing code, solving problems — one full stack at a time. JavaScript Enthusiast | Backend & Frontend Dev | Cloud-ready Solutions.

💡 Personal & Friendly: Turning coffee into code & ideas into products ☕💻 I build full stack apps that actually work 😎 Dev by day, debugger by night 🔧

💼 Focused & Tech-Specific: AdonisJS & Vue.js Developer | Cloud & DevOps Explorer Building modern web apps using TypeScript, Node.js & AWS Code + Cloud = ❤️ | Full Stack @ Webledger

When building robust apps with AdonisJS, there are times you might want to use an external mailing service that isn't natively supported. Fortunately, AdonisJS makes it easy to extend the @adonisjs/mail module with your own custom mail driver.

In this guide, I’ll show how I built a custom mail driver for a third-party service (like Zepto, Mailgun alternative, etc.) and how you can plug it right into Adonis’s mail system using configuration and IoC bindings.

🛠️ Step 1: Add Driver Config

First, define your custom driver in config/mail.ts:

// config/mail.ts

customMailDriver: {
  driver: 'customMailDriver',
  config: {
    token: Env.get('MAIL_TOKEN')
  },
},

Here, we call it customMailDriver just as a reference. You can name your driver anything.


🧾 Step 2: Extend Mail Contracts

Update the contracts/mail.ts file to register your custom driver and config type:

// contracts/mail.ts

import CustomMailDriver, { CustomMailDriverConfig } from '../providers/CustomMailDriver'

declare module '@ioc:Adonis/Addons/Mail' {
  interface MailDrivers {
    customMailDriver: {
      config: CustomMailDriverConfig
      implementation: CustomMailDriver
    }
  }

  interface MailersList {
    customMailDriver: CustomMailDriverConfig
  }
}

This tells Adonis that your app supports a new driver and what types it uses.


🧩 Step 3: Register the Driver in the App Provider

Now wire it all together in providers/AppProvider.ts:

// providers/AppProvider.ts

public async boot() {
  const { default: CustomMailDriver } = await import('providers/CustomMailDriver')
  const Mail = this.app.container.use('Adonis/Addons/Mail')

  Mail.extend('customMailDriver', (_mail, _mapping, config: any) => {
    return new CustomMailDriver(config)
  })
}

This uses Adonis’s Mail.extend() method to bind your driver implementation with the framework.


📦 Step 4: Create Your Custom Driver

Here’s the implementation of your actual driver logic in providers/CustomMailDriver.ts:

// providers/CustomMailDriver.ts

export type CustomMailDriverConfig = {
  driver: string
  config: {
    token: string
  }
  implementation?: any
}

export default class CustomMailDriver implements MailDriverContract {
  private mailClient: SendMailClient

  constructor(private driverConfig: CustomMailDriverConfig) {
    const url = 'api.custommail.com/' // hypothetical base URL
    this.mailClient = new SendMailClient({
      url,
      token: this.driverConfig.config.token
    })
  }

  public async send(message: MessageNode | any, config: {
    [key: string]: any
    payload?: {
      // Define optional payload fields
    }
  }): Promise<void> {
    const messagePayload = {
      from: message.from?.address,
      to: message.to?.[0]?.address,
      subject: message.subject,
      content: message.html || message.text,
      // ...other payload structure
    }

    await this.mailClient
      .sendMail(messagePayload)
      .then((resp) => {
        // handle success
        return resp
      })
      .catch((error) => {
        // handle errors
        throw error
      })
  }

  public async close() {
    // Clean up if needed
  }
}

📬 How to Use Your Custom Mailer

Now, sending an email is as simple as:

await Mail.use('customMailDriver').send((message) => {
  message
    .to('user@example.com')
    .from('admin@yourapp.com')
    .subject('Hello from custom driver')
    .html('<strong>It works!</strong>')
})

Everything plugs in seamlessly using Adonis’s mail API. ✅


💡 Why Create a Custom Driver?

  • Integrate with any third-party email provider

  • Customize payloads for specialized features (e.g. templates, tags)

  • Fine-tune retry and error handling behavior

  • Stick to Adonis’s clean and elegant syntax


🧵 Final Thoughts

Custom drivers in AdonisJS give you the flexibility to use any external service without sacrificing the developer experience. With a bit of setup, your own mailer works just like any built-in one.

Let me know if you'd like to see the same setup for queue-based mailing or advanced logging with this custom driver.