Product

Golang send email: Send transactional email with Go in minutes

We've released a new Golang wrapper that will make it easier than ever to manage contacts and process email.
August 29, 2025

If you’re building with Go and need reliable email for sign-ups, receipts, password resets, or alerts, this guide shows the fastest path. 

You’ll set up a sender, send your first message with Mailjet’s Go SDK, and learn patterns for templates, attachments, bulk sending, webhooks, and SMTP. 

This is an example-first, production-ready approach to email integration.

Back in 2009, Google released a language called Go, often referred to as “Golang”. Go was introduced as a robust server-side programming language. Since then, it has never failed to fulfill its promises with low-level programming patterns and powerful data structures.

Who this guide is for

This guide is designed for:

  • Developers and DevOps engineers who want a simple, durable “send email in Go” solution
  • Teams who care about deliverability, analytics, and scale without the complexity of SMTP management

Prerequisites

Before getting started, you’ll need:

  • A Mailjet account with API and Secret keys
  • A validated sender email/domain (SPF and DKIM recommended for optimal inbox placement)
  • Go 1.20+ (the SDK supports Go 1.13+) and access to set environment variables

💡 Pro tip: Authenticate your domain via SPF/DKIM to improve inbox delivery rates. See the complete authentication guide for setup details and examples.

Quickstart: Send your first Go email (API v3.1)

Let’s get you sending emails quickly using the official Mailjet Go SDK and the v3.1 Send API.

1. Install dependencies and set API keys

First, install the Mailjet Go SDK:

                            

                                go get github.com/mailjet/mailjet-apiv3-go/v4
                            
                        

Then set your environment variables:

                            

                                export MJ_APIKEY_PUBLIC=your_api_key
export MJ_APIKEY_PRIVATE=your_secret_key
export SENDER_EMAIL=your_verified_sender@yourdomain.com
                            
                        

2. Create your first email program

Create a main.go file with the following code:

                            

                                package main

import (
    "fmt"
    "log"
    "os"

    "github.com/mailjet/mailjet-apiv3-go/v4"
)

func main() {
    mj := mailjet.NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

    msgs := []mailjet.InfoMessagesV31{
        {
            From: &mailjet.RecipientV31{Email: os.Getenv("SENDER_EMAIL"), Name: "Go App"},
            To: &mailjet.RecipientsV31{
                {Email: "recipient@example.com", Name: "Recipient"},
            },
            Subject:  "Hello from Go + Mailjet",
            TextPart: "This is a plain-text fallback.",
            HTMLPart: "<h3>Hello from Go + Mailjet</h3><p>It works.</p>",
        },
    }

    messages := mailjet.MessagesV31{Info: msgs}
    res, err := mj.SendMailV31(&messages)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Status: %+v\n", res)
}

                            
                        

Why this works

The Go SDK wraps Mailjet’s REST endpoints and provides a convenient SendMailV31 helper that accepts a Messages array. This approach gives you the full power of the Mailjet API with minimal code.

Send via SMTP in go (standard library)

If you prefer SMTP or already use an SMTP MTA, you can use Mailjet’s SMTP relay with your API credentials.

                            

                                package main

import (
    "net/smtp"
    "os"
)

func main() {
    host := "in-v3.mailjet.com"
    auth := smtp.PlainAuth("", os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"), host)

    to := []string{"recipient@example.com"}
    from := "sender@yourdomain.com"
    msg := []byte(
        "To: recipient@example.com\r\n" +
            "From: Go App <sender@yourdomain.com>\r\n" +
            "Subject: SMTP from Go via Mailjet\r\n" +
            "MIME-Version: 1.0\r\n" +
            "Content-Type: text/html; charset=UTF-8\r\n\r\n" +
            "<p>Hello via SMTP</p>",
    )

    // Port 587 (TLS) or 465 (SSL) are common choices
    err := smtp.SendMail(host+":587", auth, from, to, msg)
    if err != nil {
        log.Fatal(err)
    }
}

                            
                        

SMTP configuration notes

  • SMTP host: in-v3.mailjet.com
  • Common ports: 587 (TLS) or 465 (SSL)
  • Port 25 considerations: May be blocked by your ISP or cloud provider

For more details, see the SMTP configuration guide.

Personalize with templates and variables

Design your email template once in the Mailjet dashboard, then pass a TemplateID and Variables from your Go code for dynamic content.

                            

                                msgs := []mailjet.InfoMessagesV31{
    {
        From:              &mailjet.RecipientV31{Email: os.Getenv("SENDER_EMAIL"), Name: "Go App"},
        To:                &mailjet.RecipientsV31{{Email: "recipient@example.com", Name: "Terry"}},
        TemplateID:        123456,    // replace with your template ID
        TemplateLanguage:  true,      // enable Mailjet templating language
        Variables:         map[string]any{"first_name": "Terry", "plan": "Pro"},
        Subject:           "Welcome, {{var:first_name:\"there\"}}",
    },
}

                            
                        

Template variable syntax

  • API variables: Use {{var:first_name:”default_value”}} to insert variables from your API call
  • Contact data: Use [[data:property:default]] for data stored in Mailjet contacts

For more template examples, see this Stack Overflow discussion.

Attach files and inline images

Send attachments and embed inline images in your emails. The total message size limit is 15 MB.

                            

                                // Read and base64-encode your files first, then:
msgs := []mailjet.InfoMessagesV31{
    {
        From: &mailjet.RecipientV31{Email: os.Getenv("SENDER_EMAIL")},
        To:   &mailjet.RecipientsV31{{Email: "recipient@example.com"}},
        Subject:  "Invoice attached + inline logo",
        HTMLPart: `<p>Thanks for your purchase!</p><img src="cid:logo1" alt="Company Logo">`,
        Attachments: &[]mailjet.AttachmentV31{
            {
                ContentType:   "application/pdf",
                Filename:      "invoice.pdf",
                Base64Content: "<BASE64_STRING>", // your base64-encoded PDF
            },
        },
        InlinedAttachments: &[]mailjet.InlinedAttachmentV31{
            {
                AttachmentV31: mailjet.AttachmentV31{
                    ContentType:   "image/png",
                    Filename:      "logo.png",
                    Base64Content: "<BASE64_PNG>", // your base64-encoded image
                },
                ContentID: "logo1", // referenced in HTML as cid:logo1
            },
        },
    },
}
                            
                        

Attachment best practices

  • Size limit: Keep total message size ≤ 15 MB
  • Bulk emails: For better deliverability, consider linking to hosted files instead of attaching large files
  • Inline images: Use the ContentID field to reference images in your HTML with cid: syntax

Send in bulk (multiple messages)

Send multiple personalized messages in a single API call. Each message is validated independently, so successful messages will be sent even if one fails.

                            

                                msgs := []mailjet.InfoMessagesV31{
    {
        From: &mailjet.RecipientV31{Email: os.Getenv("SENDER_EMAIL")},
        To:   &mailjet.RecipientsV31{{Email: "user1@example.com"}},
        Subject: "Welcome, User 1!",
        HTMLPart: "<p>Hello User 1</p>",
    },
    {
        From: &mailjet.RecipientV31{Email: os.Getenv("SENDER_EMAIL")},
        To:   &mailjet.RecipientsV31{{Email: "user2@example.com"}},
        Subject: "Welcome, User 2!",
        HTMLPart: "<p>Hello User 2</p>",
    },
}

res, err := mj.SendMailV31(&mailjet.MessagesV31{Info: msgs})
if err != nil {
    log.Fatal(err)
}

// Process results - each message gets its own status and ID
for i, result := range res.ResultsV31 {
    fmt.Printf("Message %d: Status=%s, MessageID=%d\n", i, result.Status, result.To[0].MessageID)
}

                            
                        

The v3.1 Send API returns per-message status and IDs, making it easy to correlate results with your original messages. Use the MessageID to track delivery status later.

Track delivery, opens, and clicks (webhooks)

Configure webhooks to receive real-time notifications about email events like delivery, opens, clicks, bounces, and unsubscribes.

Setting up webhooks

  1. Register your webhook endpoint in the Mailjet dashboard under “Event Tracking”
  2. Or use the /v3/REST/eventcallbackurl API endpoint programmatically

Webhook handler example

                            

                                package main

import (
    "encoding/json"
    "net/http"
    "log"
)

type MailjetEvent struct {
    Event     string `json:"event"`
    Time      int64  `json:"time"`
    MessageID int64  `json:"MessageID"`
    Email     string `json:"email"`
    URL       string `json:"url,omitempty"`    // for click events
    Error     string `json:"error,omitempty"`  // for bounce/error events
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    defer r.Body.Close()

    var events []MailjetEvent
    if err := json.NewDecoder(r.Body).Decode(&events); err != nil {
        http.Error(w, "bad request", http.StatusBadRequest)
        return
    }

    // Process events (consider using a queue for production)
    for _, event := range events {
        switch event.Event {
        case "sent":
            log.Printf("Message %d sent to %s", event.MessageID, event.Email)
        case "open":
            log.Printf("Message %d opened by %s", event.MessageID, event.Email)
        case "click":
            log.Printf("Message %d clicked by %s (URL: %s)", event.MessageID, event.Email, event.URL)
        case "bounce":
            log.Printf("Message %d bounced for %s: %s", event.MessageID, event.Email, event.Error)
        }
    }

    // Always return 200 to acknowledge receipt
    w.WriteHeader(http.StatusOK)
}

func main() {
    http.HandleFunc("/mj/events", webhookHandler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

                            
                        

Webhook best practices

  • Return HTTP 200 quickly to acknowledge receipt
  • Process events asynchronously to avoid timeouts
  • Handle retries: Mailjet retries non-200 responses for up to 24 hours

For complete event documentation, see the Event Tracking API guide.

Deliverability essentials

Here are three deliverability essentials to keep in mind.

1. Domain authentication

    Set up SPF and DKIM authentication for your sending domain to improve inbox placement and reduce the risk of spoofing:

    • SPF Record: Authorizes Mailjet to send emails on behalf of your domain
    • DKIM Signing: Adds cryptographic signatures to verify email authenticity

    Follow the complete domain authentication guide for step-by-step setup instructions.

    2. Regional configuration

      If your Mailjet account is on the US infrastructure, configure the SDK to use the US API endpoint:

                                  
      
                                      // For US region accounts
      mj := mailjet.NewMailjetClient(apiKey, secretKey)
      mj.SetAPIBase("https://api.us.mailjet.com/v3.1/")
      
                                  
                              

      3. SMTP configuration

        • Default region: in-v3.mailjet.com
        • Recommended ports: 587 (TLS) or 465 (SSL)

        Firewall considerations: Test your network’s port access; many providers block port 25

        Troubleshooting common issues

        Here are the most common issues and how to troubleshoot them.

        Authentication errors (401 unauthorized)

        • Check your API keys are correctly set in environment variables
        • Verify the API region: Use api.us.mailjet.com for US accounts, api.mailjet.com for EU accounts

        Content validation errors (400 bad request)

        • “At least HTMLPart, TextPart or TemplateID must be provided”: Ensure you include email content or specify a template ID
        • Missing required fields: Verify From, To, and Subject are properly set

        Message size errors (413 payload too large)

        • Check total message size: Keep attachments and content under 15 MB total
        • Consider alternatives: For large files, use hosted links instead of attachments

        Webhook issues

        • Events not being captured: Ensure your webhook endpoint returns HTTP 200 status
        • Processing timeouts: Handle webhook processing asynchronously to avoid blocking Mailjet’s retry mechanism

        Frequently asked questions

        What’s the quickest way to send an email in Go?

        Use the official SDK with SendMailV31 as shown in the Quickstart section. It’s a single function call once your API keys are configured.

        Can I send emails using SMTP instead of the API?

        Yes! Point Go’s net/smtp package at in-v3.mailjet.com using your API key and secret as credentials, with port 587 or 465.

        How do I personalize email templates?

        Set TemplateID, enable TemplateLanguage: true, and pass your data in the Variables field. Use {{var:name:”default”}} syntax in your templates.

        Where can I view delivery and engagement metrics?

        Use webhooks for real-time event data, or check the Mailjet dashboard and REST API statistics endpoints for aggregated metrics.

        Next steps

        Now that you have email sending working in your Go application, consider these enhancements:

        1. Secure your sender reputation: Authenticate your domain with SPF and DKIM records
        2. Add event tracking: Implement webhooks to power analytics and automated workflows
        3. Explore advanced features: Check out URLTags and SandboxMode for testing in the Send API v3.1 documentation
        4. Browse more examples: Visit the Go SDK repository for additional patterns and use cases

        With this foundation, you’re ready to build robust, scalable email functionality into your Go applications. The combination of Mailjet’s reliable infrastructure and Go’s performance makes for a powerful email solution.