Examples
Typescript
- TypeScript Overview
- Examples
Python
- Python Integration Overview
- Examples
Javascript
- JavaScript Overview
- Examples
PHP
- PHP Integration Overview
- Examples
cURL
Examples
Using SMTP with Go
Send emails via SMTP using Go’s net/smtp package
Go SMTP Integration
Send emails using Go’s built-in net/smtp package with Shoutbox’s SMTP server.
Without Our Library
Using only Go’s standard library net/smtp
package:
Copy
package main
import (
"fmt"
"net/smtp"
)
func main() {
// SMTP server configuration
host := "smtp.shoutbox.net"
port := 587
auth := smtp.PlainAuth(
"",
"shoutbox",
"YOUR_API_KEY",
host,
)
// Email content
from := "[email protected]"
to := []string{"[email protected]"}
msg := []byte("From: [email protected]\r\n" +
"To: [email protected]\r\n" +
"Subject: Hello World\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n" +
"\r\n" +
"<h1>Welcome!</h1>\r\n")
err := smtp.SendMail(
fmt.Sprintf("%s:%d", host, port),
auth,
from,
to,
msg,
)
if err != nil {
panic(err)
}
}
With Our Library
For a more feature-rich experience, use our Go library which provides type safety, attachments, and easier email composition:
Installation
Copy
go get github.com/shoutboxnet/shoutbox-go/shoutbox
Quick Start
Copy
package main
import (
"log"
"os"
"github.com/shoutboxnet/shoutbox-go/shoutbox"
)
func main() {
client := shoutbox.NewSMTPClient(os.Getenv("SHOUTBOX_API_KEY"))
msg := &shoutbox.EmailMessage{
From: "[email protected]",
To: []string{"[email protected]"},
Subject: "Hello World",
HTML: "<h1>Welcome!</h1>",
}
err := client.SendEmail(msg)
if err != nil {
log.Fatal(err)
}
}
Library Implementation Details
SMTP Client Structure
Copy
// This is what the library provides internally
package shoutbox
import (
"bytes"
"encoding/base64"
"fmt"
"mime/multipart"
"net/smtp"
"net/textproto"
"os"
"path/filepath"
"strings"
)
type SMTPClient struct {
Host string
Port int
Username string
Password string
Auth smtp.Auth
}
func NewSMTPClient(apiKey string) *SMTPClient {
host := "smtp.shoutbox.net"
return &SMTPClient{
Host: host,
Port: 587,
Username: "shoutbox",
Password: apiKey,
Auth: smtp.PlainAuth("", "shoutbox", apiKey, host),
}
}
type EmailMessage struct {
From string
To []string
Subject string
HTML string
Name string
ReplyTo string
Attachments []Attachment
Headers map[string]string
}
type Attachment struct {
Filename string
Content []byte
ContentType string
}
func (c *SMTPClient) SendEmail(msg *EmailMessage) error {
buffer := &bytes.Buffer{}
writer := multipart.NewWriter(buffer)
// Add headers
headers := textproto.MIMEHeader{}
headers.Set("From", formatAddress(msg.From, msg.Name))
headers.Set("To", strings.Join(msg.To, ", "))
headers.Set("Subject", msg.Subject)
headers.Set("MIME-Version", "1.0")
headers.Set("Content-Type", fmt.Sprintf("multipart/mixed; boundary=%s", writer.Boundary()))
if msg.ReplyTo != "" {
headers.Set("Reply-To", msg.ReplyTo)
}
// Add custom headers
for key, value := range msg.Headers {
headers.Set(key, value)
}
// Write headers
for key, values := range headers {
for _, value := range values {
fmt.Fprintf(buffer, "%s: %s\r\n", key, value)
}
}
buffer.WriteString("\r\n")
// Add HTML part
htmlPart, err := writer.CreatePart(textproto.MIMEHeader{
"Content-Type": {"text/html; charset=UTF-8"},
"Content-Transfer-Encoding": {"quoted-printable"},
})
if err != nil {
return fmt.Errorf("error creating HTML part: %w", err)
}
htmlPart.Write([]byte(msg.HTML))
// Add attachments
for _, attachment := range msg.Attachments {
part, err := writer.CreatePart(textproto.MIMEHeader{
"Content-Type": {fmt.Sprintf("%s; name=%q", attachment.ContentType, attachment.Filename)},
"Content-Disposition": {fmt.Sprintf("attachment; filename=%q", attachment.Filename)},
"Content-Transfer-Encoding": {"base64"},
})
if err != nil {
return fmt.Errorf("error creating attachment part: %w", err)
}
encoder := base64.NewEncoder(base64.StdEncoding, part)
encoder.Write(attachment.Content)
encoder.Close()
}
writer.Close()
// Send email
err = smtp.SendMail(
fmt.Sprintf("%s:%d", c.Host, c.Port),
c.Auth,
msg.From,
msg.To,
buffer.Bytes(),
)
if err != nil {
return fmt.Errorf("error sending email: %w", err)
}
return nil
}
func formatAddress(email, name string) string {
if name == "" {
return email
}
return fmt.Sprintf("%s <%s>", name, email)
}
Basic Request Structure
Field | Type | Required | Description |
---|---|---|---|
from | string | Yes | Sender email address |
to | []string | Yes | Recipient email address(es) |
subject | string | Yes | Email subject line |
html | string | Yes | HTML content of the email |
name | string | No | Sender name |
replyTo | string | No | Reply-to email address |
Recipients
Multiple Recipients
Copy
client := shoutbox.NewSMTPClient(os.Getenv("SHOUTBOX_API_KEY"))
msg := &shoutbox.EmailMessage{
From: "[email protected]",
To: []string{"[email protected]", "[email protected]"},
Subject: "Team Update",
HTML: "<h1>Important Announcement</h1>",
}
err := client.SendEmail(msg)
if err != nil {
log.Fatal(err)
}
Named Recipients
Copy
msg := &shoutbox.EmailMessage{
From: "[email protected]",
Name: "Notification System",
To: []string{"John Doe <[email protected]>", "Jane Smith <[email protected]>"},
Subject: "Team Meeting",
HTML: "<h1>Meeting Invitation</h1>",
}
err := client.SendEmail(msg)
if err != nil {
log.Fatal(err)
}
Reply-To Address
Copy
msg := &shoutbox.EmailMessage{
From: "[email protected]",
To: []string{"[email protected]"},
ReplyTo: "Support Team <[email protected]>",
Subject: "Support Ticket Update",
HTML: "<h1>Your ticket has been updated</h1>",
}
err := client.SendEmail(msg)
if err != nil {
log.Fatal(err)
}
Attachments
Helper Functions for Attachments
Copy
// shoutbox/helpers.go
package shoutbox
import (
"fmt"
"io"
"mime"
"os"
"path/filepath"
)
func NewAttachmentFromFile(filepath string) (Attachment, error) {
content, err := os.ReadFile(filepath)
if err != nil {
return Attachment{}, fmt.Errorf("error reading file: %w", err)
}
// Detect content type
contentType := mime.TypeByExtension(filepath.Ext(filepath))
if contentType == "" {
contentType = "application/octet-stream"
}
return Attachment{
Filename: filepath.Base(filepath),
Content: content,
ContentType: contentType,
}, nil
}
func NewAttachmentFromReader(reader io.Reader, filename string) (Attachment, error) {
content, err := io.ReadAll(reader)
if err != nil {
return Attachment{}, fmt.Errorf("error reading content: %w", err)
}
contentType := mime.TypeByExtension(filepath.Ext(filename))
if contentType == "" {
contentType = "application/octet-stream"
}
return Attachment{
Filename: filename,
Content: content,
ContentType: contentType,
}, nil
}
Complete Example with Attachments
Copy
// Create attachments
pdfAttachment, err := shoutbox.NewAttachmentFromFile("january_report.pdf")
if err != nil {
log.Fatal(err)
}
xlsAttachment, err := shoutbox.NewAttachmentFromFile("data.xlsx")
if err != nil {
log.Fatal(err)
}
msg := &shoutbox.EmailMessage{
From: "[email protected]",
Name: "Reports Team",
To: []string{"John Smith <[email protected]>"},
Subject: "Monthly Report - January 2024",
HTML: "<h1>Monthly Report</h1><p>Please find your report attached.</p>",
Attachments: []shoutbox.Attachment{pdfAttachment, xlsAttachment},
}
err = client.SendEmail(msg)
if err != nil {
log.Fatal(err)
}
Custom Headers
Complete Example with Headers
Copy
msg := &shoutbox.EmailMessage{
From: "[email protected]",
Name: "Newsletter Team",
To: []string{"Subscriber <[email protected]>"},
ReplyTo: "Newsletter Support <[email protected]>",
Subject: "Your Weekly Newsletter",
HTML: "<h1>This Week's Updates</h1><p>Latest news and updates...</p>",
Headers: map[string]string{
"List-Unsubscribe": "<https://yourdomain.com/unsubscribe>",
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
"X-Campaign-ID": "newsletter_2024_01",
"X-Mailer": "ShoutboxAPI/1.0",
"Precedence": "bulk",
"X-Auto-Response-Suppress": "OOF, AutoReply",
},
}
err := client.SendEmail(msg)
if err != nil {
log.Fatal(err)
}
Security Best Practices
API Key Management
Use environment variables for API keys:
Copy
apiKey := os.Getenv("SHOUTBOX_API_KEY")
if apiKey == "" {
log.Fatal("SHOUTBOX_API_KEY environment variable is not set")
}
Error Handling
Implement proper error handling:
Copy
type SMTPError struct {
Op string
Err error
}
func (e *SMTPError) Error() string {
return fmt.Sprintf("smtp error during %s: %v", e.Op, e.Err)
}
func (e *SMTPError) Unwrap() error {
return e.Err
}
// Usage
if err := client.SendEmail(msg); err != nil {
var smtpErr *SMTPError
if errors.As(err, &smtpErr) {
log.Printf("SMTP error: %v", err)
} else {
log.Printf("Unknown error: %v", err)
}
return
}
Rate Limiting
Use rate limiting:
Copy
import "golang.org/x/time/rate"
type RateLimitedSMTPClient struct {
*SMTPClient
limiter *rate.Limiter
}
func NewRateLimitedSMTPClient(apiKey string, rps float64) *RateLimitedSMTPClient {
return &RateLimitedSMTPClient{
SMTPClient: NewSMTPClient(apiKey),
limiter: rate.NewLimiter(rate.Limit(rps), 1),
}
}
func (c *RateLimitedSMTPClient) SendEmail(msg *EmailMessage) error {
if err := c.limiter.Wait(context.Background()); err != nil {
return err
}
return c.SMTPClient.SendEmail(msg)
}
Email Validation
Validate email addresses:
Copy
import "net/mail"
func validateEmail(email string) error {
_, err := mail.ParseAddress(email)
return err
}
func validateEmailList(emails []string) error {
for _, email := range emails {
if err := validateEmail(email); err != nil {
return fmt.Errorf("invalid email %q: %w", email, err)
}
}
return nil
}
Rate Limits
The same rate limits apply to both SMTP and REST API usage:
- 60 requests per minute per API key
- Maximum attachment size: 10MB
- Maximum recipients per email: 50
Please contact support if you need higher limits for your use case.
Support
For additional support or questions, please contact our support team.
On this page
- Go SMTP Integration
- Without Our Library
- With Our Library
- Installation
- Quick Start
- Library Implementation Details
- SMTP Client Structure
- Basic Request Structure
- Recipients
- Multiple Recipients
- Named Recipients
- Reply-To Address
- Attachments
- Helper Functions for Attachments
- Complete Example with Attachments
- Custom Headers
- Complete Example with Headers
- Security Best Practices
- Rate Limits
- Support
Assistant
Responses are generated using AI and may contain mistakes.