go-notificationgo-notification
Getting Started

Quick Start

Send your first notification in five minutes.

This walks through sending an email via Mailgun — but the same pattern applies to every channel.

1. Create the notifier

main.go
notifier := notification.New(notification.Config{
    // Zero value is valid: async worker pool (10 workers), 3 retries,
    // 1s exponential backoff, slog.Default() logger.
})
defer notifier.Close()

Close() takes no arguments. It shuts down the worker pool and waits for in-flight deliveries to finish, so always defer it.

2. Register a channel

A channel is a driver — a concrete implementation. Each driver reports its own name (via Name()), which is the string you list in Via. For mail drivers the default name is "mail".

main.go
notifier.RegisterChannel(mailgun.New(mailgun.Config{
    Domain: "mg.example.com",
    APIKey: os.Getenv("MAILGUN_API_KEY"),
    From:   mail.Address{Name: "Acme", Address: "noreply@example.com"},
}))

RegisterChannel takes a single argument — the driver. The sender address is a mail.Address struct, not a plain string.

To register the same driver type twice (e.g. transactional vs. marketing mail), give each one a distinct name through the driver's ChannelName field, then reference those names in Via. See Channels Overview.

3. Implement Notifiable on your user type

Notifiable tells go-notification how to identify and reach a recipient. It has two methods — GetID() and RouteNotificationFor() — both returning string:

main.go
type User struct {
    ID    string
    Name  string
    Email string
}

func (u User) GetID() string { return u.ID }

func (u User) RouteNotificationFor(channel string) string {
    switch channel {
    case "mail":
        return u.Email
    }
    return "" // empty string = skip this channel for this user
}

4. Define a notification

A notification is any struct that implements Notification (the Via method). For each channel it targets, add the matching To<Channel> method — ToMail returns a *mail.Message:

main.go
type OrderShipped struct {
    OrderID string
}

func (n OrderShipped) Via(notifiable notification.Notifiable) []string {
    return []string{"mail"}
}

func (n OrderShipped) ToMail(notifiable notification.Notifiable) *mail.Message {
    return mail.NewMessage().
        SetSubject("Your order has shipped").
        SetGreeting("Hi there!").
        Line("Your order " + n.OrderID + " is on its way.").
        Action("Track package", "https://example.com/track/"+n.OrderID)
}

The builder uses Set* verbs (SetSubject, SetGreeting), plus Line and Action for the Laravel-style body.

5. Send it

main.go
user := User{ID: "1", Name: "Dani", Email: "dani@example.com"}
notifier.Send(context.Background(), user, OrderShipped{OrderID: "A-1024"})

That's the end-to-end loop. With the default async config, Send returns immediately and dispatch runs on the worker pool — delivery errors surface through Config.OnError. Pass notification.Sync() to block until delivery completes.