Documentation
¶
Overview ¶
Package render provides email template rendering functionality using the Hermes library. It offers a high-level API for generating both HTML and plain text email content with support for themes, text direction, and template variable replacement.
Overview ¶
The render package wraps the github.com/go-hermes/hermes/v2 library to provide an easy-to-use interface for creating professional-looking transactional emails. It supports multiple themes, bidirectional text, and rich content including tables, actions, and custom formatting.
Key Features ¶
- Multiple visual themes (Default, Flat)
- Bidirectional text support (LTR/RTL)
- Template variable replacement with {{variable}} syntax
- Rich content support (tables, actions, buttons, dictionary entries)
- HTML and plain text generation
- Configuration via struct with validation
- Deep cloning for concurrent operations
- Integration with github.com/nabbar/golib/errors for structured error handling
Basic Usage ¶
Creating a simple email:
mailer := render.New()
mailer.SetName("My Company")
mailer.SetLink("https://example.com")
mailer.SetLogo("https://example.com/logo.png")
mailer.SetTheme(render.ThemeFlat)
body := &hermes.Body{
Name: "John Doe",
Intros: []string{"Welcome to our service!"},
Outros: []string{"Thank you for signing up."},
}
mailer.SetBody(body)
htmlBuf, err := mailer.GenerateHTML()
textBuf, err := mailer.GeneratePlainText()
Configuration-Based Usage ¶
Using a configuration struct (suitable for JSON/YAML/TOML):
config := render.Config{
Theme: "flat",
Direction: "ltr",
Name: "My Company",
Link: "https://example.com",
Logo: "https://example.com/logo.png",
Copyright: "© 2024 My Company",
TroubleText: "Need help? Contact support@example.com",
Body: hermes.Body{
Name: "John Doe",
Intros: []string{"Welcome!"},
},
}
if err := config.Validate(); err != nil {
// Handle validation error
}
mailer := config.NewMailer()
htmlBuf, err := mailer.GenerateHTML()
Template Variable Replacement ¶
The package supports template variable replacement with the {{variable}} syntax:
mailer := render.New()
mailer.SetName("{{company}}")
body := &hermes.Body{
Name: "{{user}}",
Intros: []string{"Your verification code is {{code}}"},
Actions: []hermes.Action{
{
Instructions: "Click below to verify:",
Button: hermes.Button{
Text: "Verify Email",
Link: "{{verification_link}}",
},
},
},
}
mailer.SetBody(body)
mailer.ParseData(map[string]string{
"{{company}}": "Acme Inc",
"{{user}}": "John Doe",
"{{code}}": "123456",
"{{verification_link}}": "https://example.com/verify?token=abc123",
})
htmlBuf, err := mailer.GenerateHTML()
Advanced Content ¶
Creating emails with tables and actions:
body := &hermes.Body{
Name: "John Doe",
Intros: []string{"Here is your monthly report:"},
Dictionary: []hermes.Entry{
{Key: "Transaction ID", Value: "TXN-123456"},
{Key: "Date", Value: "2024-01-15"},
},
Tables: []hermes.Table{{
Data: [][]hermes.Entry{
{
{Key: "Item", Value: "Product A"},
{Key: "Quantity", Value: "2"},
{Key: "Price", Value: "$50.00"},
},
{
{Key: "Item", Value: "Product B"},
{Key: "Quantity", Value: "1"},
{Key: "Price", Value: "$30.00"},
},
},
Columns: hermes.Columns{
CustomWidth: map[string]string{
"Item": "50%",
"Quantity": "20%",
"Price": "30%",
},
},
}},
Actions: []hermes.Action{
{
Instructions: "View full details:",
Button: hermes.Button{
Text: "View Invoice",
Link: "https://example.com/invoice/123456",
},
},
},
Outros: []string{"Thank you for your business!"},
}
mailer.SetBody(body)
htmlBuf, err := mailer.GenerateHTML()
Themes ¶
The package supports multiple themes:
- ThemeDefault: Classic, centered email design
- ThemeFlat: Modern, minimalist email design
Theme selection:
mailer.SetTheme(render.ThemeFlat)
// or
theme := render.ParseTheme("flat")
mailer.SetTheme(theme)
Text Direction ¶
Support for both LTR and RTL languages:
// For LTR languages (English, French, Spanish, etc.)
mailer.SetTextDirection(render.LeftToRight)
// For RTL languages (Arabic, Hebrew, Persian, etc.)
mailer.SetTextDirection(render.RightToLeft)
// Or parse from string
direction := render.ParseTextDirection("rtl")
mailer.SetTextDirection(direction)
Thread Safety ¶
Mailer instances are not thread-safe. For concurrent operations, use Clone():
baseMailer := render.New()
baseMailer.SetName("My Company")
baseMailer.SetTheme(render.ThemeFlat)
// Create independent copies for concurrent use
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
mailer := baseMailer.Clone()
body := &hermes.Body{
Name: fmt.Sprintf("User %d", index),
}
mailer.SetBody(body)
htmlBuf, _ := mailer.GenerateHTML()
// Send email...
}(i)
}
wg.Wait()
Error Handling ¶
The package uses github.com/nabbar/golib/errors for structured error handling:
htmlBuf, err := mailer.GenerateHTML()
if err != nil {
if err.Code() == render.ErrorMailerHtml {
// Handle HTML generation error
}
log.Printf("Error: %v", err)
}
Error codes:
- ErrorParamEmpty: Required parameters are missing
- ErrorMailerConfigInvalid: Configuration validation failed
- ErrorMailerHtml: HTML generation failed
- ErrorMailerText: Plain text generation failed
Integration with Email Sending ¶
The generated content can be used with various email sending packages:
mailer := render.New()
// ... configure mailer ...
htmlBuf, err := mailer.GenerateHTML()
textBuf, err := mailer.GeneratePlainText()
// Using standard net/smtp
msg := "From: sender@example.com\r\n" +
"To: recipient@example.com\r\n" +
"Subject: Welcome\r\n" +
"MIME-Version: 1.0\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n\r\n" +
htmlBuf.String()
// Or use github.com/nabbar/golib/mail/smtp for full SMTP support
Dependencies ¶
This package depends on:
- github.com/go-hermes/hermes/v2: Email template rendering engine
- github.com/nabbar/golib/errors: Structured error handling
- github.com/go-playground/validator/v10: Configuration validation
Performance Considerations ¶
- Email generation typically takes 1-5ms depending on content complexity
- Clone operations are fast (~1µs for simple, ~10µs for complex content)
- Template variable replacement is performed in-place with O(n*m) complexity
- CSS inlining (default) adds processing time but improves email client compatibility
Best Practices ¶
- Always validate configuration before creating a mailer from Config
- Use Clone() for concurrent operations to avoid race conditions
- Generate both HTML and plain text versions for better compatibility
- Test emails in multiple email clients (Gmail, Outlook, Apple Mail, etc.)
- Keep logo images under 200KB for faster loading
- Use HTTPS URLs for all links and images
- Include clear call-to-action buttons with descriptive text
- Provide a plain text alternative for accessibility
Related Packages ¶
For complete email workflow:
- github.com/nabbar/golib/mail/smtp: SMTP client for sending emails
- github.com/nabbar/golib/mail/sender: High-level email sending with attachments
- github.com/nabbar/golib/errors: Error handling and logging
References ¶
For more information on email body structure and available fields:
- Hermes documentation: https://github.com/go-hermes/hermes
- Email best practices: https://www.campaignmonitor.com/best-practices/
Index ¶
Constants ¶
const ( // ErrorParamEmpty indicates that required parameters are missing or empty. // This error is returned when mandatory configuration or data is not provided. ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgMailer // ErrorMailerConfigInvalid indicates that the mailer configuration is invalid. // This error is returned by Config.Validate() when validation fails. ErrorMailerConfigInvalid // ErrorMailerHtml indicates a failure during HTML email generation. // This typically occurs when the Hermes library encounters an error // while processing the email template. ErrorMailerHtml // ErrorMailerText indicates a failure during plain text email generation. // This typically occurs when the Hermes library encounters an error // while converting the email to plain text format. ErrorMailerText )
Error codes for the render package. These codes are used with the github.com/nabbar/golib/errors package to provide structured error handling.
All error codes start from liberr.MinPkgMailer to avoid conflicts with other packages in the golib ecosystem.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Theme specifies the email template theme ("default" or "flat")
Theme string `json:"theme,omitempty" yaml:"theme,omitempty" toml:"theme,omitempty" mapstructure:"theme,omitempty" validate:"required"`
// Direction specifies the text direction ("ltr" or "rtl")
Direction string `` /* 135-byte string literal not displayed */
// Name is the product/company name displayed in the email
Name string `json:"name,omitempty" yaml:"name,omitempty" toml:"name,omitempty" mapstructure:"name,omitempty" validate:"required"`
// Link is the primary product/company URL (must be a valid URL)
Link string `json:"link,omitempty" yaml:"link,omitempty" toml:"link,omitempty" mapstructure:"link,omitempty" validate:"required,url"`
// Logo is the URL of the logo image (must be a valid URL)
Logo string `json:"logo,omitempty" yaml:"logo,omitempty" toml:"logo,omitempty" mapstructure:"logo,omitempty" validate:"required,url"`
// Copyright is the copyright text displayed in the footer
Copyright string `` /* 135-byte string literal not displayed */
// TroubleText is the help/support text displayed for troubleshooting
TroubleText string `` /* 143-byte string literal not displayed */
// DisableCSSInline controls whether to disable CSS inlining in HTML output
DisableCSSInline bool `` /* 143-byte string literal not displayed */
// Body contains the email body content structure
// See github.com/go-hermes/hermes/v2 Body for field details
Body libhms.Body `json:"body" yaml:"body" toml:"body" mapstructure:"body" validate:"required"`
}
Config represents the configuration structure for creating a Mailer instance. It supports multiple serialization formats (JSON, YAML, TOML) and includes validation tags for ensuring configuration correctness.
All fields except DisableCSSInline are required and must pass validation. The Link and Logo fields must be valid URLs.
This struct is designed to be used with configuration files or environment variables via libraries like Viper or similar configuration management tools.
Example JSON configuration:
{
"theme": "flat",
"direction": "ltr",
"name": "My Company",
"link": "https://example.com",
"logo": "https://example.com/logo.png",
"copyright": "© 2024 My Company",
"troubleText": "Need help? Contact support@example.com",
"disableCSSInline": false,
"body": {
"name": "John Doe",
"intros": ["Welcome to our service!"]
}
}
func (Config) NewMailer ¶
NewMailer creates a new Mailer instance from the configuration. It parses the theme and direction strings and initializes all fields.
Note: This method does not validate the configuration. Call Validate() before NewMailer() to ensure the configuration is valid.
Returns:
- A configured Mailer instance ready to use
Example:
config := render.Config{
Theme: "flat",
Direction: "ltr",
Name: "My Company",
Link: "https://example.com",
Logo: "https://example.com/logo.png",
Copyright: "© 2024",
TroubleText: "Need help?",
Body: hermes.Body{Name: "User"},
}
if err := config.Validate(); err == nil {
mailer := config.NewMailer()
htmlBuf, _ := mailer.GenerateHTML()
}
func (Config) Validate ¶
Validate validates the Config struct using validator tags. It checks all required fields and validates URL formats for Link and Logo.
Returns:
- nil if validation succeeds
- liberr.Error containing all validation errors if validation fails
Validation rules:
- All fields except DisableCSSInline are required
- Link must be a valid URL
- Logo must be a valid URL
Example:
config := render.Config{
Theme: "flat",
Direction: "ltr",
Name: "Company",
Link: "https://example.com",
Logo: "https://example.com/logo.png",
Copyright: "© 2024",
TroubleText: "Help",
Body: hermes.Body{},
}
if err := config.Validate(); err != nil {
// Handle validation errors
}
type Mailer ¶
type Mailer interface {
// Clone creates a deep copy of the Mailer instance.
// All slices and nested structures are copied independently to avoid
// shared references, making the clone safe for concurrent use.
Clone() Mailer
// SetTheme sets the visual theme for the email template.
// Available themes: ThemeDefault, ThemeFlat
SetTheme(t Themes)
// GetTheme returns the currently configured theme.
GetTheme() Themes
// SetTextDirection sets the text direction for the email content.
// Use LeftToRight for LTR languages, RightToLeft for RTL languages.
SetTextDirection(d TextDirection)
// GetTextDirection returns the currently configured text direction.
GetTextDirection() TextDirection
// SetBody sets the email body content.
// See github.com/go-hermes/hermes/v2 Body for structure details.
SetBody(b *hermes.Body)
// GetBody returns the current email body content.
GetBody() *hermes.Body
// SetCSSInline controls CSS inlining in HTML output.
// Set to true to disable CSS inlining (useful for some email clients).
SetCSSInline(disable bool)
// SetName sets the product/company name displayed in the email.
SetName(name string)
// GetName returns the configured product/company name.
GetName() string
// SetCopyright sets the copyright text displayed in the email footer.
SetCopyright(copy string)
// GetCopyright returns the configured copyright text.
GetCopyright() string
// SetLink sets the primary product/company link (usually a URL).
SetLink(link string)
// GetLink returns the configured product/company link.
GetLink() string
// SetLogo sets the URL of the logo image displayed in the email header.
SetLogo(logoUrl string)
// GetLogo returns the configured logo URL.
GetLogo() string
// SetTroubleText sets the help/support text displayed when actions fail.
// Example: "Having trouble? Contact support@example.com"
SetTroubleText(text string)
// GetTroubleText returns the configured trouble text.
GetTroubleText() string
// ParseData replaces template variables in all email content.
// Variables in the format "{{key}}" are replaced with corresponding values.
// This affects all text fields including product info, body content, tables, and actions.
//
// Example:
// data := map[string]string{
// "{{user}}": "John Doe",
// "{{code}}": "123456",
// }
// mailer.ParseData(data)
ParseData(data map[string]string)
// GenerateHTML generates the HTML version of the email.
// Returns a buffer containing the complete HTML document.
GenerateHTML() (*bytes.Buffer, liberr.Error)
// GeneratePlainText generates the plain text version of the email.
// Returns a buffer containing formatted plain text content.
GeneratePlainText() (*bytes.Buffer, liberr.Error)
}
Mailer defines the interface for generating and managing email templates. It provides methods to configure email properties, manage template data, and generate both HTML and plain text versions of emails.
The Mailer uses the github.com/go-hermes/hermes/v2 library for template rendering and supports features like:
- Theme selection (Default, Flat)
- Text direction (LTR, RTL)
- Template variable replacement
- Product information (name, logo, link, copyright)
- Rich body content (intros, outros, tables, actions)
Thread Safety: Mailer instances are not thread-safe. Use Clone() to create independent copies for concurrent operations.
Example:
mailer := render.New()
mailer.SetName("My Company")
mailer.SetTheme(render.ThemeFlat)
body := &hermes.Body{
Name: "John Doe",
Intros: []string{"Welcome to our service!"},
}
mailer.SetBody(body)
htmlBuf, err := mailer.GenerateHTML()
func New ¶
func New() Mailer
New creates a new Mailer instance with default configuration. The default configuration includes:
- Theme: ThemeDefault
- Text Direction: LeftToRight
- CSS Inlining: Enabled
- Empty product information and body content
Example:
mailer := render.New()
mailer.SetName("My Company")
mailer.SetLink("https://example.com")
type TextDirection ¶
type TextDirection uint8
TextDirection represents the text reading direction for email content. This affects how the email content is laid out and displayed in email clients.
Common use cases:
- LeftToRight: For languages like English, French, Spanish, etc.
- RightToLeft: For languages like Arabic, Hebrew, Persian, etc.
const ( // LeftToRight indicates left-to-right text direction. // Used for most Western languages (English, French, Spanish, German, etc.). LeftToRight TextDirection = iota // RightToLeft indicates right-to-left text direction. // Used for RTL languages (Arabic, Hebrew, Persian, Urdu, etc.). RightToLeft )
func ParseTextDirection ¶
func ParseTextDirection(direction string) TextDirection
ParseTextDirection parses a text direction string and returns the corresponding TextDirection enum. The parsing is case-insensitive and supports multiple formats.
Supported formats:
- "ltr", "LTR" -> LeftToRight
- "rtl", "RTL" -> RightToLeft
- "left", "left-to-right", "Left->Right" -> LeftToRight
- "right", "right-to-left", "Right->Left" -> RightToLeft
If the direction string is not recognized or empty, LeftToRight is returned as the default.
Example:
dir := render.ParseTextDirection("rtl")
dir = render.ParseTextDirection("right-to-left")
dir = render.ParseTextDirection("RTL")
dir = render.ParseTextDirection("unknown") // Returns LeftToRight
func (TextDirection) String ¶
func (d TextDirection) String() string
String returns the string representation of the text direction.
Returns:
- "Left->Right" for LeftToRight
- "Right->Left" for RightToLeft
Example:
dir := render.RightToLeft fmt.Println(dir.String()) // Output: "Right->Left"
type Themes ¶
type Themes uint8
Themes represents the available email template themes. Each theme provides a different visual style for the generated emails.
The themes are based on github.com/go-hermes/hermes/v2 theme implementations.
func ParseTheme ¶
ParseTheme parses a theme name string and returns the corresponding Themes enum value. The parsing is case-insensitive.
Supported theme names:
- "default" -> ThemeDefault
- "flat" -> ThemeFlat
If the theme name is not recognized, ThemeDefault is returned.
Example:
theme := render.ParseTheme("flat")
theme = render.ParseTheme("FLAT") // Also works
theme = render.ParseTheme("unknown") // Returns ThemeDefault