go-notificationgo-notification
Channels

Channel Overview

All 24 drivers at a glance — pricing, free tiers, and when to use each.

go-notification ships with seven channel families. Every family has multiple driver choices so you can match cost, deliverability, and compliance needs.

Quick Comparison

ChannelDriversFree OptionsPaid OptionsBest For
Email7SMTP, Mailgun (100/day), SES (3k/mo)SendGrid, PostmarkTransactional email
WhatsApp5WAHA Core (self-hosted)Fonnte, Twilio, MetaCustomer comms (ID)
SMS4Twilio trial, SNS (100/mo)Twilio, ZenzivaOTP, alerts
Chat5All freeInternal team notifs
Push1FCM (unlimited)Mobile app notifs
Database1Built-inIn-app notifications
Webhook1Built-inCustom integrations

By family

Email (7 drivers)

SMTP, Mailgun, SendGrid, AWS SES, Resend, Postmark, Mailtrap. Start with the Email Overview for driver comparison and cloud port-blocking warnings.

WhatsApp (5 drivers)

WAHA, Fonnte, Wablas, Twilio WhatsApp, Meta Cloud API. See the WhatsApp Overview for official vs. unofficial API tradeoffs.

SMS (4 drivers)

Twilio, Zenziva, Vonage (Nexmo), AWS SNS.

Chat (5 drivers)

Slack, Telegram, Discord, Microsoft Teams.

Push (1 driver)

Firebase Cloud Messaging (FCM) — iOS, Android, and Web.

Database (1 driver — 3 backends)

Database channel — in-app notifications stored in Postgres, MySQL, or SQLite.

Webhook (1 driver)

Generic HTTP POST for any custom integration.

Registering channels

A channel is registered by its driver. The name it reports from Name() is the string you use in Notification.Via and RouteNotificationFor. Defaults per family:

FamilyDefault Name()
Email"mail"
SMS"sms"
Chat (Slack, Telegram, Discord, Teams)"chat"
WhatsApp"whatsapp"
Push"push"
Webhook"webhook"
Database"database"
main.go
notifier.RegisterChannel(mailgun.New(mailgun.Config{ /* ... */ }))
// registered as "mail" → Via returns []string{"mail"}

Multiple instances of one driver

Silent overwrite if Config.Name is empty

RegisterChannel keys by the driver's Name(). Two drivers reporting the same name silently overwrite — the second wins, no error, no warning.

The trap: Slack, Telegram, Discord, and Teams all default to "chat". Registering more than one without setting Config.Name means only the last one is reachable. The same applies to two mail drivers (both "mail"), two SMS drivers ("sms"), etc. Always set a distinct Config.Name when registering more than one driver from the same family.

To run more than one instance of a family — transactional vs. marketing mail, or Slack and Telegram — give each a distinct name via its Config.Name field:

main.go
notifier.RegisterChannel(mailgun.New(mailgun.Config{Name: "mail_tx", /* ... */}))
notifier.RegisterChannel(sendgrid.New(sendgrid.Config{Name: "mail_mk", /* ... */}))

notifier.RegisterChannel(slack.New(slack.Config{Name: "slack", /* ... */}))
notifier.RegisterChannel(telegram.New(telegram.Config{Name: "telegram", /* ... */}))

Then reference those names everywhere:

main.go
func (n Promo) Via(notification.Notifiable) []string { return []string{"mail_mk", "slack"} }

func (u User) RouteNotificationFor(channel string) string {
    switch channel {
    case "mail_tx", "mail_mk": return u.Email
    case "slack":              return u.SlackWebhook
    case "telegram":           return u.TelegramChatID
    }
    return ""
}

Decision guides

Picking the right provider matters more than the code you write around it. Dedicated guides: