mailgun-go

repository·main·Indexed 20 days ago

https://github.com/mailgun/mailgun-go

A Go library for interacting with the Mailgun API. It supports sending emails (including HTML and templates), event tracking, email validation, and webhook handling. The library provides functionality to manage API keys, configure alerts, retrieve account or domain metrics, and handle bounce records. Version 5 requires the /v5 suffix in import paths.

Tokens
31.6K
Snippets
144
Records
162
Agent score
73%

What's inside mailgun-go

  1. Migrate from v4 to v5

    main

    To migrate to v5, follow these steps:

    1. Upgrade to the latest v4 release (v4.23.0) first.
    2. Remove all deprecated code (use a linter like staticcheck with SA1019 to find // Deprecated: comments).
    3. Update your import paths to include /v5, for example: import "github.com/mailgun/mailgun-go/v5".
  2. Handle Mailgun Webhooks and verify signatures

    main

    To securely handle webhooks, set a signing key using mg.SetWebhookSigningKey(key). When a request arrives, decode the mtypes.WebhookPayload, verify the signature using mg.VerifyWebhookSignature(payload.Signature), and then parse the event data using events.ParseEvent(payload.EventData).

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"net/http"
    	"os"
    
    	"github.com/mailgun/mailgun-go/v5"
    	"github.com/mailgun/mailgun-go/v5/events"
    	"github.com/mailgun/mailgun-go/v5/mtypes"
    )
    
    func main() {
    	mg := mailgun.NewMailgun("MAILGUN_API_KEY")
    	mg.SetWebhookSigningKey("WEBHOOK_SIGNING_KEY")
    
    	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    		var payload mtypes.WebhookPayload
    		if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
    			fmt.Printf("decode JSON error: %s", err)
    			w.WriteHeader(http.StatusNotAcceptable)
    			return
    		}
    
    		verified, err := mg.VerifyWebhookSignature(payload.Signature)
    		if err != nil {
    			fmt.Printf("verify error: %s\n", err)
    			w.WriteHeader(http.StatusNotAcceptable)
    			return
    		}
    
    		if !verified {
    			w.WriteHeader(http.StatusNotAcceptable)
    			fmt.Printf("failed verification %+v\n", payload.Signature)
    			return
    		}
    
    		fmt.Printf("Verified Signature\n")
    
    		e, err := events.ParseEvent(payload.EventData)
    		if err != nil {
    			fmt.Printf("parse event error: %s\n", err)
    			return
    		}
    
    		switch event := e.(type) {
    		case *events.Accepted:
    			fmt.Printf("Accepted: auth: %t\n", event.Flags.IsAuthenticated)
    		case *events.Delivered:
    			fmt.Printf("Delivered transport: %s\n", event.Envelope.Transport)
    		}
    	})
    
    	fmt.Println("Serve on :9090...")
    	if err := http.ListenAndServe(":9090", nil); err != nil {
    		fmt.Printf("serve error: %s\n", err)
    		os.Exit(1)
    	}
    }
  3. Use Mailgun Templates

    main

    Templates allow you to manage layouts on the Mailgun server and populate variables at send-time. Use message.SetTemplate(templateName) and message.AddTemplateVariable(key, value) to inject data into the template. The variables are sent as a JSON stringified X-Mailgun-Variables header.

    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"time"
    
    	"github.com/mailgun/mailgun-go/v5"
    )
    
    var yourDomain = "your-domain-name"
    var apiKey = "MAILGUN_API_KEY"
    
    func main() {
    	mg := mailgun.NewMailgun(apiKey)
    
    	sender := "sender@example.com"
    	subject := "Fancy subject!"
    	body := ""
    	recipient := "recipient@example.com"
    
    	message := mailgun.NewMessage(yourDomain, sender, subject, body, recipient)
    	message.SetTemplate("passwordReset")
    	err := message.AddTemplateVariable("passwordResetLink", "some link to your site unique to your user")
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    	defer cancel()
    
    	resp, err := mg.Send(ctx, message)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	fmt.Printf("ID: %s Resp: %s\n", resp.ID, resp.Message)
    }
  4. How MemberListIterator works

    main

    The MemberListIterator is a stateful iterator used for navigating paginated mailing list member results. It wraps a mtypes.MemberListResponse and provides methods to move through the pages of the API response.

    • First(ctx, items): Sets the iterator to the first page and populates items.
    • Next(ctx, items): Fetches the next page of results. Returns false when no more pages exist.
    • Previous(ctx, items): Moves to the previous page.
    • Last(ctx, items): Moves to the last page (requires First() or Next() to have been called first).
    • Err(): Returns any error encountered during the iteration process.
  5. Iterate through mailing lists

    main

    To retrieve and navigate through multiple pages of mailing lists, use ListMailingLists. This returns a *ListsIterator which allows for paginated traversal.

    Iteration Methods

    • First(ctx, *[]mtypes.MailingList) bool: Retrieves the first page of items.
    • Next(ctx, *[]mtypes.MailingList) bool: Retrieves the next page of items. Returns false when no more pages exist or an error occurs.
    • Previous(ctx, *[]mtypes.MailingList) bool: Retrieves the previous page of items.
    • Last(ctx, *[]mtypes.MailingList) bool: Retrieves the last page of items. (Must call First or Next before calling Last).
    • Err() error: Returns any error encountered during iteration.
    iterator := mg.ListMailingLists(&mailgun.ListOptions{Limit: 10})
    
    // Start with the first page
    var items []mtypes.MailingList
    if iterator.First(ctx, &items) {
        fmt.Println("First page items:", items)
    }
    
    // Iterate through subsequent pages
    for iterator.Next(ctx, &items) {
        fmt.Println("Next page items:", items)
    }
    
    if err := iterator.Err(); err != nil {
        log.Fatal(err)
    }
  6. How EventIterator works

    main

    An EventIterator manages the state required to page through Mailgun events. It wraps an events.Response which contains paging metadata (Next, First, Last, Previous URLs).

    Paging Methods

    • First(ctx, ee): Fetches the very first page of events.
    • Next(ctx, ee): Fetches the next page of events. Returns false when no more pages exist or an error occurs.
    • Last(ctx, ee): Fetches the last page. Note: This is invalid unless First() or Next() has been called first.
    • Previous(ctx, ee): Fetches the previous page. Returns false if no previous page exists.

    All methods populate the provided slice ee *[]events.Event with the results of the current page. Always check iterator.Err() after a method returns false to determine if the termination was due to an error or simply reaching the end of the data.

  7. How CredentialsIterator works

    main

    The CredentialsIterator is a stateful object used to navigate through paginated credential lists. It embeds mtypes.CredentialsListResponse, providing access to the TotalCount of credentials available.

    Workflow

    1. Initialize: Call ListCredentials(domain, opts) to get an iterator.
    2. Fetch: Use First() to start or Next() to move forward. These methods perform the actual API request and populate the provided slice.
    3. Check Errors: Always check iterator.Err() after a loop or a failed navigation attempt to see if the failure was due to a network or API error.
    4. Navigation: The iterator tracks its own offset and limit internally to manage pagination via the skip and limit parameters in the underlying API calls.
  8. Configure the EU Region

    main

    If your Mailgun domain is hosted in the EU region, you must change the default API base using mg.SetAPIBase(mailgun.APIBaseEU).

    mg := mailgun.NewMailgun("MAILGUN_API_KEY")
    mg.SetAPIBase(mailgun.APIBaseEU)
  9. Iterate through large result sets with List iterators

    main

    Methods starting with List (e.g., ListEvents, ListDomains) return an iterator. This allows you to page through large datasets efficiently without loading everything into memory at once.

    To use an iterator:

    1. Call the List method with ListOptions (you can specify a Limit per page, up to a maximum of 100).
    2. Use a for it.Next(ctx, &page) loop to fetch subsequent pages.
    3. Ensure you provide a context.Context with a timeout to prevent the operation from hanging indefinitely.
    mg := mailgun.NewMailgun("MAILGUN_API_KEY")
    // Request 100 items per page
    it := mg.ListEvents(&mailgun.ListEventOptions{Limit: 100})
    
    // Use a context to prevent long-running operations
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
    defer cancel()
    
    var page []mailgun.Event
    for it.Next(ctx, &page) {
        for _, e := range page {
            // Process event 'e'
        }
    }
  10. How TagIterator pagination works

    main

    The TagIterator provides several methods to navigate through pages of tags. It embeds mtypes.TagsResponse, giving you access to the current Items and Paging information.

    • Next(ctx context.Context, items *[]mtypes.Tag) bool: Fetches the next page of items. Returns true if new items were loaded, false otherwise.
    • Previous(ctx context.Context, items *[]mtypes.Tag) bool: Fetches the previous page of items.
    • First(ctx context.Context, items *[]mtypes.Tag) bool: Returns to the first page of results.
    • Last(ctx context.Context, items *[]mtypes.Tag) bool: Jumps to the last page of results.
    • Err() error: Returns any error encountered during pagination or fetching.
  11. List and iterate through subaccounts

    main

    To retrieve a list of subaccounts, use ListSubaccounts. This returns a SubaccountsIterator which allows for paginated traversal of your subaccounts.

    Configuration

    Pass a *ListSubaccountsOptions to control the results:

    • Limit: Number of items per page (defaults to 10 if 0).
    • Skip: Number of items to skip.
    • SortArray: Field to sort by.
    • Enabled: Filter by enabled status.

    Iteration Methods

    • First(ctx, *[]mtypes.Subaccount) bool: Retrieves the first page. Returns false on error.
    • Next(ctx, *[]mtypes.Subaccount) bool: Retrieves the next page. Returns false when no more pages exist or an error occurs.
    • Last(ctx, *[]mtypes.Subaccount) bool: Retrieves the last page. Note: Must be called after First() or Next().
    • Previous(ctx, *[]mtypes.Subaccount) bool: Retrieves the previous page.
    • Err() error: Returns any error encountered during iteration.
    • Offset() int: Returns the current offset of the iterator.
    opts := &mailgun.ListSubaccountsOptions{
        Limit: 20,
        Enabled: true,
    }
    iterator := mg.ListSubaccounts(opts)
    
    var subaccounts []mtypes.Subaccount
    for iterator.Next(ctx, &subaccounts) {
        // Process subaccounts page by page
        fmt.Println(subaccounts)
    }
    
    if err := iterator.Err(); err != nil {
        // Handle iteration error
    }