Message Builders
Fluent, chainable builders for every channel. Minimal surface area, maximum readability.
Every channel exposes a message builder via NewMessage(). The builders are designed to be:
- Chainable — each method returns the builder so you can write it as one expression.
- Channel-specific —
mail.MessagehasSetSubject(),whatsapp.MessagehasSetImage(), etc. No leaky common base. - Validation-light — builders don't try to validate upstream provider rules (that's the driver's job). They only guard against obvious local mistakes (nil payload, empty required fields).
Message types live under github.com/gopackx/go-notification/channel/<family>. Slack, Telegram, Discord, and Teams all share the single chat family — there is no per-provider message type.
The Laravel-style builder (SetGreeting / Line / Action / SetSalutation) auto-renders to a clean HTML template and a plain-text fallback at send time:
import "github.com/gopackx/go-notification/channel/mail"
mail.NewMessage().
SetSubject("Your order shipped").
SetGreeting("Hi, Dani"). // optional
Line("Your order A-1024 is on its way.").
Action("Track package", "https://..."). // renders as button
Line("Thanks for shopping with us.").
SetSalutation("— The team") // optionalSender, recipients, addressing
SetFrom, AddTo, AddCC, AddBCC, and AddReplyTo each take an address plus an optional display name. You can call the Add* variants multiple times to build a list:
mail.NewMessage().
SetFrom("noreply@example.com", "Example").
AddTo("dani@example.com", "Dani").
AddCC("ops@example.com").
AddBCC("audit@example.com").
AddReplyTo("support@example.com", "Support")If you don't set To, the channel falls back to RouteNotificationFor("mail").
Raw HTML and plain text
For full control, set the body directly. Provide both SetText and SetHTML so clients that prefer plain text get a usable version:
mail.NewMessage().
SetSubject("Welcome").
SetText("Welcome — open https://app.example.com/dashboard to get started.").
SetHTML(renderedHTML)See Email Templates for mail.TemplateRenderer (renders a Go html/template into Message.HTML).
Attachments
Attach takes a single mail.Attachment struct, not three positional args:
mail.NewMessage().
Attach(mail.Attachment{
Filename: "invoice.pdf",
ContentType: "application/pdf",
Data: pdfBytes,
})For inline images (CID references in HTML), set Inline and ContentID:
mail.NewMessage().
SetHTML(`<p>Logo: <img src="cid:logo"></p>`).
Attach(mail.Attachment{
Filename: "logo.png",
ContentType: "image/png",
Data: logoBytes,
Inline: true,
ContentID: "logo",
})Priority
SetPriority accepts one of three constants — providers that support priority (Mailgun, SendGrid, …) map them to their headers; others ignore the value:
mail.NewMessage().SetPriority(mail.PriorityHigh)
// mail.PriorityNormal (default), mail.PriorityHigh, mail.PriorityLowHeaders, tags, metadata
For provider-side analytics, suppression lists, and routing:
mail.NewMessage().
AddHeader("X-Campaign-ID", campaignID). // raw SMTP/HTTP header
AddTag("welcome", "onboarding"). // appears in Mailgun/SendGrid analytics
SetMetadata("user_id", userID). // key/value provider metadata
SetMetadata("plan", "pro")AddTag is variadic — pass several tags in one call. SetMetadata is key-by-key. Both are best-effort: drivers only forward what their provider supports.
import "github.com/gopackx/go-notification/channel/whatsapp"
whatsapp.NewMessage().
SetText("Hi! Your OTP is *" + code + "*. Valid 5 minutes.")With media — SetImage takes the URL and a caption together:
whatsapp.NewMessage().
SetImage("https://cdn.example.com/invoice.jpg", "Your invoice")Template (for Twilio/Meta official APIs). SetTemplate takes the template
name, language, and any positional parameters:
whatsapp.NewMessage().
SetTemplate("otp_v2", "en", code).
SetText("Your code: " + code) // fallback textSMS
import "github.com/gopackx/go-notification/channel/sms"
sms.NewMessage().SetText("Your OTP: " + code)SMS is deliberately minimal — no rich content, no attachments. Beyond SetText
there's only SetTo and SetFrom. Anything more is a different channel.
Push (FCM)
import "github.com/gopackx/go-notification/channel/push"
push.NewMessage().
SetTitle("Order shipped").
SetBody("Track it now").
SetBadge(1).
SetSound("default").
SetData("order_id", "A-1024")The push payload is provider-agnostic: target with SetToken / SetTokens /
SetTopic, and pass custom key/value pairs through SetData (values are
strings). Platform-specific config is left to the driver.
Chat (Slack, Telegram, Discord, Teams)
All four chat providers use one chat.Message. The common SetText works
everywhere; provider-specific richness is added with dedicated methods and
fields.
import "github.com/gopackx/go-notification/channel/chat"
chat.NewMessage().SetText("Deploy started")Slack attachments:
chat.NewMessage().
SetText("Deploy started").
AddSlackAttachment(chat.SlackAttachment{
Color: "good",
Title: "Build",
Fields: []chat.SlackField{
{Title: "Service", Value: svc, Short: true},
{Title: "Env", Value: env, Short: true},
},
Footer: "CI",
})Telegram uses SetParseMode and a couple of Telegram-specific fields set
directly on the struct:
msg := chat.NewMessage().
SetText("*Alert*\nBuild failed on `main`").
SetParseMode("MarkdownV2")
msg.TelegramDisableWebPreview = trueDiscord embeds:
chat.NewMessage().
SetText("Build failed").
AddDiscordEmbed(chat.DiscordEmbed{
Title: "CI #1234",
Color: 0xFF0000,
Fields: []chat.DiscordField{
{Name: "Branch", Value: "main", Inline: true},
},
})Teams uses the MessageCard schema via the TeamsCard field:
msg := chat.NewMessage().SetText("Deploy to prod")
msg.TeamsCard = map[string]any{
"title": "Deploy",
"text": "Environment: prod",
}Database
import "github.com/gopackx/go-notification/channel/database"
database.NewMessage().
SetType("order.shipped").
SetTitle("Order shipped").
SetBody("Your order is on its way.").
AddData("order_id", orderID)Use AddData to attach payload keys one at a time, or SetData to replace the
whole map at once.
Webhook
import "github.com/gopackx/go-notification/channel/webhook"
webhook.NewMessage().
SetURL("https://hooks.example.com/notify").
SetMethod("POST").
SetJSON(map[string]any{"event": "order.shipped", "order_id": id}).
AddHeader("X-Idempotency-Key", idempotencyKey)Choose the body encoding with SetJSON, SetForm, or SetRaw.
Why fluent builders
The builders are optimized for reading a notification spec next to its sending code — what you type in ToMail() should match what the mail looks like without mental translation. Struct literals lose that property once you have more than three fields.