Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DE-1146 Release v5 #367

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e4a2914
DE-1386 removed deprecated (mg *MailgunImpl) NewMessage method (#365)
vtopc Dec 15, 2024
34b51e0
DE-1387 Remove func (mg *MailgunImpl) NewMIMEMessage(…) *Message  (#366)
vtopc Dec 15, 2024
a2a4cfd
DE-1388 (mg *MailgunImpl) Send should accept interface, not struct (#…
vtopc Dec 15, 2024
528746b
updated README.md
vtopc Dec 15, 2024
2a99c6b
Merge branch 'master' into v5.0.0-RC1
vtopc Dec 18, 2024
9b43e40
Merge branch 'master' into v5.0.0-RC1
vtopc Dec 18, 2024
7e12fef
DE-1394 Remove deprecated v3 Validation (#371)
vtopc Dec 18, 2024
317cfaa
DE-1392 Remove deprecated GetStats (#372)
vtopc Dec 24, 2024
7de53aa
DE-1410 Remove deprecated GetStoredMessageForURL() and GetStoredMessa…
vtopc Dec 24, 2024
02ff37c
DE-1411 Remove deprecated VerifyWebhookRequest() method (#374)
vtopc Dec 24, 2024
7933fc9
DE-1390 Remove CaptureCurlOutput (#375)
vtopc Dec 24, 2024
49c465a
DE-1384 Domain agnostic API (#376)
vtopc Dec 25, 2024
1c49eb6
DE-1383 Move the API version out of the base URL (#377)
vtopc Jan 3, 2025
54c03d7
DE-1383 Move the API version out of the base URL 2 (#378)
vtopc Jan 3, 2025
0d43085
DE-1394 Removed deprecated v3 validation fields (#379)
vtopc Jan 6, 2025
d4a15d9
DE-1384 Domain agnostic client(fix example) (#380)
vtopc Jan 6, 2025
461bd27
Merge branch 'master' into v5.0.0-RC1
vtopc Jan 30, 2025
c776f64
DE-1412 Move ValidateEmail() to MailgunImpl (#383)
vtopc Feb 1, 2025
ab04aef
DE-1416 Switch subaccounts to v5 (#384)
vtopc Feb 1, 2025
0f1c234
merged master
vtopc Feb 6, 2025
3290874
backport #386 (#387)
vtopc Feb 6, 2025
a340883
Merge branch 'master' into v5.0.0-RC1
vtopc Feb 9, 2025
fe7c6ae
DE-1417 Switch domains to v4 (#388)
vtopc Feb 9, 2025
8394945
DE-1389 Make Webhook Signing Key optional (#390)
vtopc Feb 10, 2025
e24803b
Merge branch 'master' into v5.0.0-RC1
vtopc Feb 20, 2025
63a2c66
DE-1449 Metrics: Remove Deprecated ESPBlockCount (#392)
vtopc Feb 20, 2025
b276043
DE-1393 Move API Mailgun requests, responses, and helper types into a…
vtopc Feb 23, 2025
d3e87f7
DE-1393 Move public mocks to subfolder (#394)
vtopc Mar 1, 2025
bcac90e
DE-1391 Enable more linters (#395)
vtopc Mar 1, 2025
ecd8b0b
DE-1146 github.com/mailgun/mailgun-go/v5 (#396)
vtopc Mar 1, 2025
5fb9d92
DE-1146 fix link to API documentation (#397)
vtopc Mar 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ linters:
- gocyclo
- noctx
- gomodguard
- unused
- nolintlint

# TODO:
# - stylecheck # TODO(v5): enable
# - unused
# - stylecheck # TODO(v6): enable

linters-settings:
gocritic:
Expand All @@ -33,10 +33,9 @@ linters-settings:
- performance
- style
disabled-checks:
- singleCaseSwitch
- hugeParam # TODO(v5): enable?
- singleCaseSwitch # redundant
- hugeParam # TODO(v6): allocations critical; enable?
- sprintfQuotedString # noisy # TODO: enable
- exitAfterDefer # TODO: enable?

errcheck:
# List of functions to exclude from checking, where each entry is a single function to exclude.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ godoc:
# TODO(vtopc): fix mocks and enable nilaway for them too?
.PHONY: nilaway
nilaway: $(NILAWAY)
$(NILAWAY) -include-pkgs="$(PACKAGE)" -test=false -exclude-errors-in-files=mock_ ./...
$(NILAWAY) -include-pkgs="$(PACKAGE)" -test=false -exclude-errors-in-files=mocks/ ./...

# linter:
GOLINT = $(GOPATH)/bin/golangci-lint
Expand Down
64 changes: 31 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Mailgun with Go

[![GoDoc](https://godoc.org/github.com/mailgun/mailgun-go?status.svg)](https://godoc.org/github.com/mailgun/mailgun-go/v4)
[![GoDoc](https://godoc.org/github.com/mailgun/mailgun-go?status.svg)](https://godoc.org/github.com/mailgun/mailgun-go/v5)
[![Build Status](https://github.com/mailgun/mailgun-go/workflows/CI/badge.svg)](https://github.com/mailgun/mailgun-go/actions/workflows/main.yml?query=branch%3Amaster)

Go library for interacting with the [Mailgun](https://mailgun.com/) [API](https://documentation.mailgun.com/en/latest/api_reference.html).
Go library for interacting with the [Mailgun](https://mailgun.com/) [API](https://documentation.mailgun.com/).

## Installation

If you are using [Go Modules](https://go.dev/wiki/Modules) make sure you
include the `/v4` at the end of your import paths
include the `/v5` at the end of your import paths
```bash
$ go get github.com/mailgun/mailgun-go/v4
$ go get github.com/mailgun/mailgun-go/v5
```

## Usage
Expand All @@ -23,7 +23,7 @@ import (
"log"
"time"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v5"
)

// Your available domain names can be found here:
Expand All @@ -36,18 +36,18 @@ var privateAPIKey = "your-private-key"

func main() {
// Create an instance of the Mailgun Client
mg := mailgun.NewMailgun(yourDomain, privateAPIKey)
//When you have an EU-domain, you must specify the endpoint:
//mg.SetAPIBase("https://api.eu.mailgun.net/v3")
mg := mailgun.NewMailgun(privateAPIKey)

// When you have an EU domain, you must specify the endpoint:
// err := mg.SetAPIBase(mailgun.APIBaseEU)

sender := "[email protected]"
subject := "Fancy subject!"
body := "Hello from Mailgun Go!"
recipient := "[email protected]"

// The message object allows you to add attachments and Bcc recipients
message := mailgun.NewMessage(sender, subject, body, recipient)
message := mailgun.NewMessage(yourDomain, sender, subject, body, recipient)

ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
Expand All @@ -72,18 +72,18 @@ import (
"fmt"
"time"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v4/events"
"github.com/mailgun/mailgun-go/v5"
"github.com/mailgun/mailgun-go/v5/events"
)

func main() {
// You can find the Private API Key in your Account Menu, under "Settings":
// (https://app.mailgun.com/settings/api_security)
mg := mailgun.NewMailgun("your-domain.com", "your-private-key")
mg := mailgun.NewMailgun("your-private-key")

it := mg.ListEvents(&mailgun.ListEventOptions{Limit: 100})
it := mg.ListEvents("your-domain.com", &mailgun.ListEventOptions{Limit: 100})

var page []mailgun.Event
var page []events.Event

// The entire operation should not take longer than 30 seconds
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
Expand Down Expand Up @@ -129,18 +129,18 @@ import (
"log"
"time"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v5"
)

func main() {
// You can find the Private API Key in your Account Menu, under "Settings":
// (https://app.mailgun.com/settings/api_security)
mg := mailgun.NewMailgun("your-domain.com", "your-private-key")
mg := mailgun.NewMailgun("your-private-key")

begin := time.Now().Add(time.Second * -3)

// Very short poll interval
it := mg.PollEvents(&mailgun.ListEventOptions{
it := mg.PollEvents("your-domain.com", &mailgun.ListEventOptions{
// Only events with a timestamp after this date/time will be returned
Begin: begin,
// How often we poll the api for new events
Expand All @@ -151,7 +151,7 @@ func main() {
defer cancel()

// Poll until our email event arrives
var page []mailgun.Event
var page []events.Event
for it.Poll(ctx, &page) {
for _, e := range page {
log.Printf("Got an event: %q (%q)", e.GetName(), e.GetID())
Expand All @@ -170,7 +170,7 @@ import (
"fmt"
"time"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v5"
)

// Your plan should include email validations.
Expand Down Expand Up @@ -203,18 +203,17 @@ import (
"net/http"
"os"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v4/events"
"github.com/mailgun/mailgun-go/v5"
"github.com/mailgun/mailgun-go/v5/events"
)

func main() {
// You can find the Private API Key in your Account Menu, under "Settings":
// (https://app.mailgun.com/settings/api_security)
mg := mailgun.NewMailgun("your-domain.com", "private-api-key")
mg := mailgun.NewMailgun("private-api-key")
mg.SetWebhookSigningKey("webhook-signing-key")

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

var payload mailgun.WebhookPayload
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
fmt.Printf("decode JSON error: %s", err)
Expand Down Expand Up @@ -271,7 +270,7 @@ import (
"log"
"time"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v5"
)

// Your available domain names can be found here:
Expand All @@ -284,13 +283,13 @@ var privateAPIKey = "your-private-key"

func main() {
// Create an instance of the Mailgun Client
mg := mailgun.NewMailgun(yourDomain, privateAPIKey)
mg := mailgun.NewMailgun(privateAPIKey)

sender := "[email protected]"
subject := "HTML email!"
recipient := "[email protected]"

message := mailgun.NewMessage(sender, subject, "", recipient)
message := mailgun.NewMessage(yourDomain, sender, subject, "", recipient)
body := `
<html>
<body>
Expand All @@ -306,7 +305,7 @@ func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()

// Send the message with a 10 second timeout
// Send the message with a 10-second timeout
resp, id, err := mg.Send(ctx, message)

if err != nil {
Expand All @@ -330,7 +329,7 @@ import (
"log"
"time"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v5"
)

// Your available domain names can be found here:
Expand All @@ -343,15 +342,15 @@ var privateAPIKey = "your-private-key"

func main() {
// Create an instance of the Mailgun Client
mg := mailgun.NewMailgun(yourDomain, privateAPIKey)
mg := mailgun.NewMailgun(privateAPIKey)

sender := "[email protected]"
subject := "Fancy subject!"
body := ""
recipient := "[email protected]"

// The message object allows you to add attachments and Bcc recipients
message := mailgun.NewMessage(sender, subject, body, recipient)
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 {
Expand Down Expand Up @@ -379,7 +378,7 @@ and click on the "Go" button at the top of the page.
European customers will need to change the default API Base to access your domains

```go
mg := mailgun.NewMailgun("your-domain.com", "private-api-key")
mg := mailgun.NewMailgun("private-api-key")
mg.SetAPIBase(mailgun.APIBaseEU)
```

Expand All @@ -390,7 +389,6 @@ mg.SetAPIBase(mailgun.APIBaseEU)
To run the tests various environment variables must be set. These are:

* `MG_DOMAIN` is the domain name - this is a value registered in the Mailgun admin interface.
* `MG_PUBLIC_API_KEY` is the Public Validation API key - you can get this value from the Mailgun [security page](https://app.mailgun.com/settings/api_security)
* `MG_API_KEY` is the Private API key - you can get this value from the Mailgun [security page](https://app.mailgun.com/settings/api_security)
* `MG_EMAIL_TO` is the email address used in various sending tests.

Expand Down
12 changes: 1 addition & 11 deletions acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,14 @@ package mailgun
import (
"fmt"
"os"
"testing"
)

// Return the variable missing which caused the test to be skipped
func SkipNetworkTest() string {
for _, env := range []string{"MG_DOMAIN", "MG_API_KEY", "MG_EMAIL_TO", "MG_PUBLIC_API_KEY"} {
for _, env := range []string{"MG_DOMAIN", "MG_API_KEY", "MG_EMAIL_TO"} {
if os.Getenv(env) == "" {
return fmt.Sprintf("'%s' missing from environment skipping...", env)
}
}
return ""
}

func spendMoney(t *testing.T, tFunc func()) {
ok := os.Getenv("MG_SPEND_MONEY")
if ok != "" {
tFunc()
} else {
t.Log("Money spending not allowed, not running function.")
}
}
51 changes: 15 additions & 36 deletions analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,31 @@ package mailgun

import (
"context"
"strings"

"github.com/mailgun/errors"
"github.com/mailgun/mailgun-go/v5/mtypes"
)

type MetricsPagination struct {
// Colon-separated value indicating column name and sort direction e.g. 'domain:asc'.
Sort string `json:"sort"`
// The number of items to skip over when satisfying the request.
// To get the first page of data set skip to zero.
// Then increment the skip by the limit for subsequent calls.
Skip int `json:"skip"`
// The maximum number of items returned in the response.
Limit int `json:"limit"`
// The total number of items in the query result set.
Total int `json:"total"`
}
type MetricsOptions = mtypes.MetricsRequest

// ListMetrics returns domain/account metrics.
//
// NOTE: Only for v1 API. To use the /v1 version define MG_URL in the environment variable
// as `https://api.mailgun.net/v1` or set `mg.SetAPIBase("https://api.mailgun.net/v1")`
// To filter by domain:
//
// opts.Filter.BoolGroupAnd = []mailgun.MetricsFilterPredicate{{
// Attribute: "domain",
// Comparator: "=",
// LabeledValues: []mailgun.MetricsLabeledValue{{Label: "example.com", Value: "example.com"}},
// }}
//
// https://documentation.mailgun.com/docs/mailgun/api-reference/openapi-final/tag/Metrics/
func (mg *MailgunImpl) ListMetrics(opts MetricsOptions) (*MetricsIterator, error) {
if !strings.HasSuffix(mg.APIBase(), "/v1") {
return nil, errors.New("only v1 API is supported")
}

domain := mg.Domain()
if domain != "" {
domainFilter := MetricsFilterPredicate{
Attribute: "domain",
Comparator: "=",
LabeledValues: []MetricsLabeledValue{{Label: domain, Value: domain}},
}

opts.Filter.BoolGroupAnd = append(opts.Filter.BoolGroupAnd, domainFilter)
}

func (mg *Client) ListMetrics(opts MetricsOptions) (*MetricsIterator, error) {
if opts.Pagination.Limit == 0 {
opts.Pagination.Limit = 10
}

req := newHTTPRequest(generatePublicApiUrl(mg, metricsEndpoint))
req.setClient(mg.Client())
req := newHTTPRequest(generateApiUrl(mg, 1, metricsEndpoint))
req.setClient(mg.HTTPClient())
req.setBasicAuth(basicAuthUser, mg.APIKey())

return &MetricsIterator{
Expand All @@ -69,7 +48,7 @@ func (iter *MetricsIterator) Err() error {
// Next retrieves the next page of items from the api. Returns false when there are
// no more pages to retrieve or if there was an error.
// Use `.Err()` to retrieve the error
func (iter *MetricsIterator) Next(ctx context.Context, resp *MetricsResponse) (more bool) {
func (iter *MetricsIterator) Next(ctx context.Context, resp *mtypes.MetricsResponse) (more bool) {
if iter.err != nil {
return false
}
Expand All @@ -84,7 +63,7 @@ func (iter *MetricsIterator) Next(ctx context.Context, resp *MetricsResponse) (m
return len(resp.Items) == iter.opts.Pagination.Limit
}

func (iter *MetricsIterator) fetch(ctx context.Context, resp *MetricsResponse) error {
func (iter *MetricsIterator) fetch(ctx context.Context, resp *mtypes.MetricsResponse) error {
if resp == nil {
return errors.New("resp cannot be nil")
}
Expand All @@ -97,7 +76,7 @@ func (iter *MetricsIterator) fetch(ctx context.Context, resp *MetricsResponse) e
}

// preallocate
resp.Items = make([]MetricsItem, 0, iter.opts.Pagination.Limit)
resp.Items = make([]mtypes.MetricsItem, 0, iter.opts.Pagination.Limit)

err = httpResp.parseFromJSON(resp)
if err != nil {
Expand Down
Loading