mailstyler

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 29, 2025 License: MIT Imports: 10 Imported by: 0

README

Go Mail Styler

Go Mail Styler is a simple and flexible Go package for sending HTML emails via SMTP with support for template rendering, CSS inlining, attachments, and inline images.


✨ Features

  • Simple API for sending HTML emails via SMTP
  • Two rendering modes: file-based templates or direct HTML content strings
  • Template rendering with dynamic data and Go template syntax
  • Built-in template functions with support for custom functions
  • CSS inlining - automatically convert external CSS to inline styles
  • Attachments & inline images - embed files and images directly in emails
  • Performance optimized - parallel CSS processing for faster rendering
  • Flexible initialization - function options pattern for clean configuration
  • Lightweight and easy to integrate

📦 Installation

go get github.com/phzeng0726/gomailstyler@v1.0.0

🚀 Quick Start

Example 1: Using Template Files
package main

import (
	"log"
	mailstyler "github.com/phzeng0726/gomailstyler"
)

func main() {
	// Initialize manager with options pattern
	// Configure SMTP password if needed for authentication
	manager, err := mailstyler.NewManager(
		mailstyler.WithSMTP("smtp.example.com", "587", "you@example.com"),
		mailstyler.WithSMTPPassword("your-password"), // Optional: for SMTP authentication
		mailstyler.WithTemplatePath("./templates"), // Optional
		mailstyler.WithCSSPath("./templates/css"), // Optional
	)
	if err != nil {
		log.Fatalf("failed to create manager: %v", err)
	}

	// Render template file with CSS inlining
	body, err := manager.RenderTemplateWithCSS("welcome.html", "styles.css", map[string]any{
		"Name": "John Doe",
	})
	if err != nil {
		log.Fatalf("failed to render template: %v", err)
	}

	// Send the email
	err = manager.SendMail(mailstyler.MailMessage{
		Subject: "Welcome to Our Service",
		Message: body,
		To:      []string{"recipient@example.com"},
	})
	if err != nil {
		log.Fatalf("failed to send mail: %v", err)
	}

	log.Println("Mail sent successfully!")
}
Example 2: Using HTML Content Strings (New in v1.0.0)
package main

import (
	"log"
	"html/template"
	mailstyler "github.com/phzeng0726/gomailstyler"
)

func main() {
	// Initialize manager (no template path needed for content mode)
	manager, err := mailstyler.NewManager(
		mailstyler.WithSMTP("smtp.example.com", "587", "you@example.com"),
	)
	if err != nil {
		log.Fatalf("failed to create manager: %v", err)
	}

	// Define HTML content as a string
	htmlContent := `
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Hello {{.Name}}</title>
</head>
<body>
	<h1>Hello, {{toUpper .Name}}!</h1>
	<p>Your order #{{.OrderID}} has been confirmed.</p>
</body>
</html>
	`

	// Render HTML content with custom functions
	body, err := manager.RenderHTMLContentWithFuncs(htmlContent, map[string]any{
		"Name":    "Jane Smith",
		"OrderID": 12345,
	}, template.FuncMap{
		"toUpper": func(s string) string {
			return strings.ToUpper(s)
		},
	})
	if err != nil {
		log.Fatalf("failed to render content: %v", err)
	}

	// Send the email
	err = manager.SendMail(mailstyler.MailMessage{
		Subject: "Order Confirmation",
		Message: body,
		To:      []string{"recipient@example.com"},
	})
	if err != nil {
		log.Fatalf("failed to send mail: %v", err)
	}

	log.Println("Mail sent successfully!")
}

🏗️ Data Structures

MailMessage

Represents an email message to be sent.

type MailMessage struct {
	Subject      string          // Email subject line
	Message      string          // HTML body content
	To           []string        // Recipient email addresses
	Cc           []string        // CC email addresses (optional)
	Attachments  []Attachment    // File attachments (optional)
	InlineImages []InlineImage   // Inline images for HTML (optional)
}
Attachment

Represents a file attachment.

type Attachment struct {
	FileName string   // Attachment filename
	Data     []byte   // File binary data
}
InlineImage

Represents an inline image embedded in HTML using cid: reference.

type InlineImage struct {
	CID      string   // Content ID for HTML reference (e.g., "logo" for <img src="cid:logo">)
	FileName string   // Image filename
	Data     []byte   // Image binary data
}

Example usage in HTML:

<img src="cid:logo" alt="Company Logo" />

📎 Working with Attachments & Inline Images

Example: Sending Email with Attachments and Inline Images
package main

import (
	"log"
	"os"
	mailstyler "github.com/phzeng0726/gomailstyler"
)

func main() {
	// Initialize manager
	manager, err := mailstyler.NewManager(
		mailstyler.WithSMTP("smtp.example.com", "587", "you@example.com"),
		mailstyler.WithSMTPPassword("your-password"),
	)
	if err != nil {
		log.Fatalf("failed to create manager: %v", err)
	}

	// Read image file for inline embedding
	logoData, err := os.ReadFile("./assets/logo.png")
	if err != nil {
		log.Fatalf("failed to read logo: %v", err)
	}

	// Read PDF file for attachment
	pdfData, err := os.ReadFile("./documents/report.pdf")
	if err != nil {
		log.Fatalf("failed to read PDF: %v", err)
	}

	// Create HTML content with inline image reference
	htmlContent := `
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Monthly Report</title>
</head>
<body>
	<img src="cid:company-logo" alt="Company Logo" width="200" />
	<h1>Monthly Report</h1>
	<p>Dear {{.Name}},</p>
	<p>Please find the attached monthly report for your review.</p>
	<img src="cid:my-doggy-img" alt="My Dog" style="border-radius: 8px;" />
	<p>Best regards,<br>The Team</p>
</body>
</html>
	`

	// Render HTML content
	body, err := manager.RenderHTMLContent(htmlContent, map[string]any{
		"Name": "John Doe",
	})
	if err != nil {
		log.Fatalf("failed to render content: %v", err)
	}

	// Read another image for inline use
	doggyData, err := os.ReadFile("./assets/my_doggy.jpg")
	if err != nil {
		log.Fatalf("failed to read doggy image: %v", err)
	}

	// Send email with attachments and inline images
	err = manager.SendMail(mailstyler.MailMessage{
		Subject: "Monthly Report - January 2024",
		Message: body,
		To:      []string{"recipient@example.com"},
		Cc:      []string{"manager@example.com"},
		// Inline images (embedded in HTML via cid:)
		InlineImages: []mailstyler.InlineImage{
			{
				CID:      "company-logo",      // Reference in HTML: <img src="cid:company-logo">
				FileName: "logo.png",
				Data:     logoData,
			},
			{
				CID:      "my-doggy-img",      // Reference in HTML: <img src="cid:my-doggy-img">
				FileName: "my_doggy.jpg",
				Data:     doggyData,
			},
		},
		// File attachments (downloadable)
		Attachments: []mailstyler.Attachment{
			{
				FileName: "monthly-report.pdf",
				Data:     pdfData,
			},
		},
	})
	if err != nil {
		log.Fatalf("failed to send mail: %v", err)
	}

	log.Println("Mail sent successfully with attachments and inline images!")
}
Key Points:

Inline Images:

  • Use Content-ID (CID) to reference images in HTML: <img src="cid:your-image-id">
  • Images are embedded in the email body (not downloadable separately)
  • Perfect for logos, banners, and visual elements
  • The CID field must match the cid: reference in your HTML

Attachments:

  • Appear as downloadable files in email clients
  • Support any file type (PDF, DOC, ZIP, images, etc.)
  • Encoded as base64 in the MIME message

Best Practices:

  • Keep inline images small to reduce email size
  • Use appropriate image formats (PNG for logos, JPG for photos)
  • Always provide alt text for accessibility
  • Test with multiple email clients (Gmail, Outlook, etc.)

📘 API Reference

Initialization
NewManager
func NewManager(opts ...ManagerOption) (*Manager, error)

Creates a new mail manager using the function options pattern.

Available options:

  • WithSMTP(server, port, sender string) - Required - SMTP server configuration
  • WithSMTPPassword(password string) - Optional - SMTP password for authentication
  • WithTemplatePath(path string) - Template directory (required for file-based rendering)
  • WithCSSPath(path string) - CSS directory (required for CSS inlining)

Example:

manager, err := mailstyler.NewManager(
	mailstyler.WithSMTP("smtp.example.com", "587", "sender@example.com"),
	mailstyler.WithSMTPPassword("your-password"),    // Optional: for SMTP auth
	mailstyler.WithTemplatePath("./templates"),      // Optional
	mailstyler.WithCSSPath("./templates/css"),       // Optional
)

Sending Mail
SendMail
func (m *Manager) SendMail(mm MailMessage) error

Sends an email with the provided message content.

Parameters:

  • mm - A MailMessage struct containing subject, HTML body, recipients, and optional attachments/inline images

MIME Structure:

  • Uses multipart/mixed for complex emails
  • HTML body encoded as text/html; charset="UTF-8"
  • Attachments use base64 encoding
  • Inline images use Content-ID headers for HTML embedding

File-Based Template Rendering
RenderTemplate
func (m *Manager) RenderTemplate(tmplFile string, data any) (string, error)

Renders an HTML template file with dynamic data.

Parameters:

  • tmplFile - Template filename (relative to template path)
  • data - Data to inject into template

Example:

body, err := manager.RenderTemplate("welcome.html", map[string]any{
	"Name": "John",
})

RenderTemplateWithFuncs
func (m *Manager) RenderTemplateWithFuncs(tmplFile string, data any, customFuncs ...template.FuncMap) (string, error)

Renders template with custom template functions. Custom functions override default functions if names conflict.

Example:

body, err := manager.RenderTemplateWithFuncs("invoice.html", data, template.FuncMap{
	"formatCurrency": func(amount float64) string {
		return fmt.Sprintf("$%.2f", amount)
	},
})

RenderTemplateWithCSS
func (m *Manager) RenderTemplateWithCSS(tmplFile, cssFile string, data any) (string, error)

Renders template with CSS file and automatically inlines styles.

Process:

  1. Template rendering and CSS file reading happen in parallel (performance optimization)
  2. CSS inserted into <head> tag
  3. CSS rules converted to inline style attributes
  4. Class attributes removed after inlining

Example:

body, err := manager.RenderTemplateWithCSS("newsletter.html", "styles.css", data)

RenderTemplateWithFuncsAndCSS
func (m *Manager) RenderTemplateWithFuncsAndCSS(tmplFile, cssFile string, data any, customFuncs ...template.FuncMap) (string, error)

Combines custom functions and CSS inlining.

Example:

body, err := manager.RenderTemplateWithFuncsAndCSS(
	"report.html",
	"report.css",
	data,
	template.FuncMap{
		"highlight": func(text string) string {
			return "<mark>" + text + "</mark>"
		},
	},
)

HTML Content Rendering (New in v1.0.0)
RenderHTMLContent
func (m *Manager) RenderHTMLContent(htmlContent string, data any) (string, error)

Renders HTML content directly from a string without file I/O.

Use cases:

  • Dynamic email generation
  • Simple emails without template files
  • Programmatic content creation

Example:

htmlContent := `<h1>Hello {{.Name}}!</h1><p>Thanks for signing up.</p>`
body, err := manager.RenderHTMLContent(htmlContent, map[string]any{
	"Name": "Alice",
})

RenderHTMLContentWithFuncs
func (m *Manager) RenderHTMLContentWithFuncs(htmlContent string, data any, customFuncs ...template.FuncMap) (string, error)

Renders HTML content with custom template functions.

Example:

htmlContent := `<h1>Order Total: {{formatPrice .Total}}</h1>`
body, err := manager.RenderHTMLContentWithFuncs(htmlContent, data, template.FuncMap{
	"formatPrice": func(price float64) string {
		return fmt.Sprintf("$%.2f", price)
	},
})

Choosing a Rendering Method
Feature File-Based Templates HTML Content Strings
File I/O Required Not required
Template Management Separate files Inline in code
CSS Inlining ✅ Supported ❌ Not supported
Custom Functions ✅ Supported ✅ Supported
Reusability High (shared template files) Medium (code-based)
Best for Complex emails, design teams Simple emails, dynamic content
Setup Requires WithTemplatePath() No path configuration needed

🧰 Default Template Functions

All rendering methods include these built-in functions:

Function Description Example
add Adds two integers {{ add 1 2 }}3
toUpper Converts to uppercase {{ toUpper "hello" }}HELLO
toLower Converts to lowercase {{ toLower "HELLO" }}hello
trim Removes leading/trailing whitespace {{ trim " text " }}text
title Title case {{ title "go mail styler" }}Go Mail Styler
formatDate Formats time.Time {{ formatDate .Time "2006-01-02" }}2025-04-23
isEmpty Checks if string is empty {{ isEmpty " " }}true
safeHTML Marks string as safe HTML {{ safeHTML "<b>bold</b>" }}
inc Increments integer by 1 {{ inc 5 }}6

Note: Custom functions override default functions if names conflict.


📂 Examples

The examples/ directory contains fully working examples:

01-template-file/ - File-Based Template Examples
  • 01-basic - Simple template rendering
  • 02-with-css - CSS inlining demonstration
  • 03-with-functions - Custom template functions
  • 04-full-featured - All features combined (template + CSS + functions + attachments + inline images)
02-html-content/ - HTML Content Examples (New in v1.0.0)
  • 01-basic - Basic HTML string rendering
  • 02-with-attachments - Content rendering with custom functions, attachments, and inline images
Running Examples
cd examples/01-template-file/01-basic
# Create .env file with SMTP configuration
go run main.go

Required .env variables:

SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SENDER=your-email@example.com
SMTP_PASSWORD=your-smtp-password    # Optional: for SMTP authentication
MAIL_RECEIVER=recipient@example.com

⚡ Performance Optimizations

Parallel CSS Processing

When using RenderTemplateWithCSS or RenderTemplateWithFuncsAndCSS:

  • Template rendering and CSS file reading execute in parallel using goroutines
  • Results synchronized via channels for optimal performance
  • Reduces total rendering time compared to sequential processing
CSS Inlining Configuration

Uses go-premailer with optimized settings:

  • KeepBangImportant: true - Preserves !important declarations
  • RemoveClasses: true - Removes class attributes after inlining (smaller HTML size)

📝 Example Template File

templates/welcome.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Welcome {{.Name}}</title>
  </head>
  <body>
    <h1>Hello, {{title .Name}}!</h1>
    <p>
      Welcome to our service. Your account was created on {{formatDate
      .SignupDate "January 2, 2006"}}.
    </p>
    <p>You have {{add .Credits 100}} bonus credits!</p>
  </body>
</html>

Corresponding CSS file (templates/css/styles.css):

body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
  margin: 0;
  padding: 20px;
}

h1 {
  color: #333;
}

p {
  color: #666;
  line-height: 1.6;
}

🪪 License

MIT


📚 Additional Resources


Made with ❤️ for Go developers who need reliable email delivery

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Attachment added in v0.2.0

type Attachment struct {
	FileName string
	Data     []byte
}

type InlineImage added in v0.2.0

type InlineImage struct {
	CID      string
	FileName string
	Data     []byte
}

type MailManager

type MailManager interface {
	SendMail(mm MailMessage) error

	// File-based rendering
	RenderTemplate(tmplFile string, data any) (string, error)
	RenderTemplateWithFuncs(tmplFile string, data any, customFuncs ...template.FuncMap) (string, error)
	RenderTemplateWithCSS(tmplFile, cssFile string, data any) (string, error)
	RenderTemplateWithFuncsAndCSS(tmplFile, cssFile string, data any, customFuncs ...template.FuncMap) (string, error)

	// Content-based rendering
	RenderHTMLContent(htmlContent string, data any) (string, error)
	RenderHTMLContentWithFuncs(htmlContent string, data any, customFuncs ...template.FuncMap) (string, error)
}

type MailMessage

type MailMessage struct {
	Subject      string
	Message      string
	To           []string
	Cc           []string
	Attachments  []Attachment
	InlineImages []InlineImage
}

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

func NewManager

func NewManager(opts ...ManagerOption) (*Manager, error)

NewManager creates a Manager using functional options pattern

func (*Manager) RenderHTMLContent added in v1.0.0

func (m *Manager) RenderHTMLContent(content string, data any) (string, error)

func (*Manager) RenderHTMLContentWithFuncs added in v1.0.0

func (m *Manager) RenderHTMLContentWithFuncs(tmplFile string, data any, customFuncs ...template.FuncMap) (string, error)

func (*Manager) RenderTemplate

func (m *Manager) RenderTemplate(tmplFile string, data any) (string, error)

func (*Manager) RenderTemplateWithCSS

func (m *Manager) RenderTemplateWithCSS(tmplFile, cssFile string, data any) (string, error)

func (*Manager) RenderTemplateWithFuncs

func (m *Manager) RenderTemplateWithFuncs(tmplFile string, data any, customFuncs ...template.FuncMap) (string, error)

func (*Manager) RenderTemplateWithFuncsAndCSS

func (m *Manager) RenderTemplateWithFuncsAndCSS(tmplFile, cssFile string, data any, customFuncs ...template.FuncMap) (string, error)

func (*Manager) SendMail

func (m *Manager) SendMail(mm MailMessage) error

type ManagerConfig added in v1.0.0

type ManagerConfig struct {
	// contains filtered or unexported fields
}

ManagerConfig holds configuration for the Manager

type ManagerOption added in v1.0.0

type ManagerOption func(*ManagerConfig)

ManagerOption is a functional option for configuring Manager

func WithCSSPath added in v1.0.0

func WithCSSPath(path string) ManagerOption

WithCSSPath sets the root path for CSS files (optional) Required only if using CSS-based rendering methods

func WithSMTP added in v1.0.0

func WithSMTP(server, port, sender string) ManagerOption

WithSMTP configures SMTP settings (required)

func WithSMTPPassword added in v1.0.0

func WithSMTPPassword(password string) ManagerOption

WithSMTPPassword sets the SMTP password for authentication (optional) If not provided, the mail will be sent without authentication

func WithTemplatePath added in v1.0.0

func WithTemplatePath(path string) ManagerOption

WithTemplatePath sets the root path for template files (optional) Required only if using file-based rendering methods