diff --git a/CHANGELOG b/CHANGELOG index 22060757..ab66201e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [3.6.1-rc.1] - 2019-06-26 +## [3.6.1-rc.3] - 2019-07-16 +### Added +* APIBaseEU and APIBaseUS to help customers change regions +* Documented how to change regions in the README + +## [3.6.1-rc.2] - 2019-07-01 ### Changes * Fix the JSON response for `GetMember()` * Typo in format string in max number of tags error diff --git a/README.md b/README.md index 995889f9..04b36541 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,13 @@ The official mailgun documentation includes examples using this library. Go [here](https://documentation.mailgun.com/en/latest/api_reference.html#api-reference) and click on the "Go" button at the top of the page. +### EU Region +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.SetAPIBase(mailgun.APIBaseEU) +``` ## Installation If you are using [golang modules](https://github.com/golang/go/wiki/Modules) make sure you diff --git a/httphelpers.go b/httphelpers.go index 515b8b9c..a74adc68 100644 --- a/httphelpers.go +++ b/httphelpers.go @@ -13,9 +13,12 @@ import ( "net/url" "os" "path" + "regexp" "strings" ) +var validURL = regexp.MustCompile(`^/v[2-4].*`) + type httpRequest struct { URL string Parameters map[string][]string @@ -291,6 +294,11 @@ func (r *httpRequest) generateUrlWithParameters() (string, error) { if err != nil { return "", err } + + if !validURL.MatchString(url.Path) { + return "", errors.New(`BaseAPI must end with a /v2, /v3 or /v4; setBaseAPI("https://host/v3")`) + } + q := url.Query() if r.Parameters != nil && len(r.Parameters) > 0 { for name, values := range r.Parameters { diff --git a/mailgun.go b/mailgun.go index 9b3a378c..9ea1e4e0 100644 --- a/mailgun.go +++ b/mailgun.go @@ -91,6 +91,8 @@ var Debug = false const ( // Base Url the library uses to contact mailgun. Use SetAPIBase() to override APIBase = "https://api.mailgun.net/v3" + APIBaseUS = APIBase + APIBaseEU = "https://api.eu.mailgun.net/v3" messagesEndpoint = "messages" mimeMessagesEndpoint = "messages.mime" bouncesEndpoint = "bounces" @@ -299,6 +301,14 @@ func (mg *MailgunImpl) SetClient(c *http.Client) { } // SetAPIBase updates the API Base URL for this client. +// // For EU Customers +// mg.SetAPIBase(mailgun.APIBaseEU) +// +// // For US Customers +// mg.SetAPIBase(mailgun.APIBaseUS) +// +// // Set a custom base API +// mg.SetAPIBase("https://localhost/v3") func (mg *MailgunImpl) SetAPIBase(address string) { mg.apiBase = address } diff --git a/mailgun_test.go b/mailgun_test.go index 27d00077..1024ff75 100644 --- a/mailgun_test.go +++ b/mailgun_test.go @@ -1,17 +1,19 @@ -package mailgun +package mailgun_test import ( + "context" "net/http" "testing" "github.com/facebookgo/ensure" + "github.com/mailgun/mailgun-go/v3" ) const domain = "valid-mailgun-domain" const apiKey = "valid-mailgun-api-key" func TestMailgun(t *testing.T) { - m := NewMailgun(domain, apiKey) + m := mailgun.NewMailgun(domain, apiKey) ensure.DeepEqual(t, m.Domain(), domain) ensure.DeepEqual(t, m.APIKey(), apiKey) @@ -21,3 +23,13 @@ func TestMailgun(t *testing.T) { m.SetClient(client) ensure.DeepEqual(t, client, m.Client()) } + +func TestInvalidBaseAPI(t *testing.T) { + mg := mailgun.NewMailgun(testDomain, testKey) + mg.SetAPIBase("https://localhost") + + ctx := context.Background() + _, err := mg.GetDomain(ctx, "unknown.domain") + ensure.NotNil(t, err) + ensure.DeepEqual(t, err.Error(), `BaseAPI must end with a /v2, /v3 or /v4; setBaseAPI("https://host/v3")`) +} diff --git a/messages_test.go b/messages_test.go index dec5df78..61f7009c 100644 --- a/messages_test.go +++ b/messages_test.go @@ -220,7 +220,7 @@ func TestSendMGOffline(t *testing.T) { ) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ensure.DeepEqual(t, req.Method, http.MethodPost) - ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/%s/messages", exampleDomain)) + ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/v3/%s/messages", exampleDomain)) ensure.DeepEqual(t, req.FormValue("from"), fromUser) ensure.DeepEqual(t, req.FormValue("subject"), exampleSubject) ensure.DeepEqual(t, req.FormValue("text"), exampleText) @@ -231,7 +231,7 @@ func TestSendMGOffline(t *testing.T) { defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") ctx := context.Background() m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser) @@ -253,7 +253,7 @@ func TestSendMGSeparateDomain(t *testing.T) { ) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ensure.DeepEqual(t, req.Method, http.MethodPost) - ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/%s/messages", signingDomain)) + ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/v3/%s/messages", signingDomain)) ensure.DeepEqual(t, req.FormValue("from"), fromUser) ensure.DeepEqual(t, req.FormValue("subject"), exampleSubject) ensure.DeepEqual(t, req.FormValue("text"), exampleText) @@ -264,7 +264,7 @@ func TestSendMGSeparateDomain(t *testing.T) { defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") ctx := context.Background() m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser) @@ -295,7 +295,7 @@ func TestSendMGMessageVariables(t *testing.T) { ) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ensure.DeepEqual(t, req.Method, http.MethodPost) - ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/%s/messages", exampleDomain)) + ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/v3/%s/messages", exampleDomain)) ensure.DeepEqual(t, req.FormValue("from"), fromUser) ensure.DeepEqual(t, req.FormValue("subject"), exampleSubject) @@ -310,7 +310,7 @@ func TestSendMGMessageVariables(t *testing.T) { defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser) m.AddVariable(exampleStrVarKey, exampleStrVarVal) @@ -368,7 +368,7 @@ func TestSendEOFError(t *testing.T) { defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser) _, _, err := mg.Send(context.Background(), m) @@ -386,13 +386,13 @@ func TestHasRecipient(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ensure.DeepEqual(t, req.Method, http.MethodPost) - ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/%s/messages", exampleDomain)) + ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/v3/%s/messages", exampleDomain)) fmt.Fprint(w, `{"message":"Queued, Thank you", "id":"<20111114174239.25659.5820@samples.mailgun.org>"}`) })) defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") // No recipient m := mg.NewMessage(fromUser, exampleSubject, exampleText) @@ -423,7 +423,7 @@ func TestResendStored(t *testing.T) { ) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ensure.DeepEqual(t, req.Method, http.MethodPost) - ensure.DeepEqual(t, req.URL.Path, "/some-url") + ensure.DeepEqual(t, req.URL.Path, "/v3/some-url") ensure.DeepEqual(t, req.FormValue("to"), toUser) rsp := fmt.Sprintf(`{"message":"%s", "id":"%s"}`, exampleMessage, exampleID) @@ -432,13 +432,13 @@ func TestResendStored(t *testing.T) { defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") - msg, id, err := mg.ReSend(context.Background(), srv.URL+"/some-url") + msg, id, err := mg.ReSend(context.Background(), srv.URL+"/v3/some-url") ensure.NotNil(t, err) ensure.DeepEqual(t, err.Error(), "must provide at least one recipient") - msg, id, err = mg.ReSend(context.Background(), srv.URL+"/some-url", toUser) + msg, id, err = mg.ReSend(context.Background(), srv.URL+"/v3/some-url", toUser) ensure.Nil(t, err) ensure.DeepEqual(t, msg, exampleMessage) ensure.DeepEqual(t, id, exampleID) @@ -454,7 +454,7 @@ func TestSendTLSOptions(t *testing.T) { ) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ensure.DeepEqual(t, req.Method, http.MethodPost) - ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/%s/messages", exampleDomain)) + ensure.DeepEqual(t, req.URL.Path, fmt.Sprintf("/v3/%s/messages", exampleDomain)) ensure.DeepEqual(t, req.FormValue("from"), fromUser) ensure.DeepEqual(t, req.FormValue("subject"), exampleSubject) ensure.DeepEqual(t, req.FormValue("text"), exampleText) @@ -467,7 +467,7 @@ func TestSendTLSOptions(t *testing.T) { defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") ctx := context.Background() m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser) @@ -497,7 +497,7 @@ func TestSendTemplate(t *testing.T) { defer srv.Close() mg := NewMailgun(exampleDomain, exampleAPIKey) - mg.SetAPIBase(srv.URL) + mg.SetAPIBase(srv.URL + "/v3") ctx := context.Background() m := mg.NewMessage(fromUser, exampleSubject, "", toUser)