Repository: mailgun/mailgun-go
Pull request #335 (2024-10-29 20:13:47)

DE-1343 Create func NewMessage and NewMIMEMessage


Patch:
diff --git a/README.md b/README.md
index f0b1eb8..7012fec 100644
--- a/README.md
+++ b/README.md
@@ -39,12 +39,12 @@ func main() {
 	recipient := "recipient@example.com"
 
 	// The message object allows you to add attachments and Bcc recipients
-	message := mg.NewMessage(sender, subject, body, recipient)
+	message := mailgun.NewMessage(sender, subject, body, recipient)
 
 	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 {
@@ -281,7 +281,7 @@ func main() {
 	subject := "HTML email!"
 	recipient := "recipient@example.com"
 
-	message := mg.NewMessage(sender, subject, "", recipient)
+	message := mailgun.NewMessage(sender, subject, "", recipient)
 	body := `
 <html>
 <body>
@@ -292,7 +292,7 @@ func main() {
 </html>
 `
 
-	message.SetHtml(body)
+	message.SetHTML(body)
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
@@ -342,7 +342,7 @@ func main() {
 	recipient := "recipient@example.com"
 
 	// The message object allows you to add attachments and Bcc recipients
-	message := mg.NewMessage(sender, subject, body, recipient)
+	message := mailgun.NewMessage(sender, subject, body, recipient)
 	message.SetTemplate("passwordReset")
 	err := message.AddTemplateVariable("passwordResetLink", "some link to your site unique to your user")
 	if err != nil {
@@ -352,9 +352,8 @@ 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 {
 		log.Fatal(err)
 	}
diff --git a/examples/examples.go b/examples/examples.go
index 10f5e78..c3f04f8 100644
--- a/examples/examples.go
+++ b/examples/examples.go
@@ -3,10 +3,11 @@ package examples
 import (
 	"context"
 	"fmt"
-	"github.com/mailgun/mailgun-go/v4"
-	"github.com/mailgun/mailgun-go/v4/events"
 	"os"
 	"time"
+
+	"github.com/mailgun/mailgun-go/v4"
+	"github.com/mailgun/mailgun-go/v4/events"
 )
 
 func AddBounce(domain, apiKey string) error {
@@ -696,7 +697,7 @@ func ResendMessage(domain, apiKey string) (string, string, error) {
 
 func SendComplexMessage(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -704,7 +705,7 @@ func SendComplexMessage(domain, apiKey string) (string, error) {
 	)
 	m.AddCC("baz@example.com")
 	m.AddBCC("bar@example.com")
-	m.SetHtml("<html>HTML version of the body</html>")
+	m.SetHTML("<html>HTML version of the body</html>")
 	m.AddAttachment("files/test.jpg")
 	m.AddAttachment("files/test.txt")
 
@@ -717,7 +718,7 @@ func SendComplexMessage(domain, apiKey string) (string, error) {
 
 func SendWithConnectionOptions(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -736,7 +737,7 @@ func SendWithConnectionOptions(domain, apiKey string) (string, error) {
 
 func SendInlineImage(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -744,7 +745,7 @@ func SendInlineImage(domain, apiKey string) (string, error) {
 	)
 	m.AddCC("baz@example.com")
 	m.AddBCC("bar@example.com")
-	m.SetHtml(`<html>Inline image here: <img alt="image" src="cid:test.jpg"/></html>`)
+	m.SetHTML(`<html>Inline image here: <img alt="image" src="cid:test.jpg"/></html>`)
 	m.AddInline("files/test.jpg")
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
@@ -756,7 +757,7 @@ func SendInlineImage(domain, apiKey string) (string, error) {
 
 func SendMessageNoTracking(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -778,7 +779,7 @@ func SendMimeMessage(domain, apiKey string) (string, error) {
 		return "", err
 	}
 
-	m := mg.NewMIMEMessage(mimeMsgReader, "bar@example.com")
+	m := mailgun.NewMIMEMessage(mimeMsgReader, "bar@example.com")
 
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
 	defer cancel()
@@ -789,7 +790,7 @@ func SendMimeMessage(domain, apiKey string) (string, error) {
 
 func SendScheduledMessage(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -806,7 +807,7 @@ func SendScheduledMessage(domain, apiKey string) (string, error) {
 
 func SendSimpleMessage(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <mailgun@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -822,7 +823,7 @@ func SendSimpleMessage(domain, apiKey string) (string, error) {
 
 func SendTaggedMessage(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hello",
 		"Testing some Mailgun awesomeness!",
@@ -843,12 +844,12 @@ func SendTaggedMessage(domain, apiKey string) (string, error) {
 
 func SendTemplateMessage(domain, apiKey string) (string, error) {
 	mg := mailgun.NewMailgun(domain, apiKey)
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <YOU@YOUR_DOMAIN_NAME>",
 		"Hey %recipient.first%",
 		"If you wish to unsubscribe, click http://mailgun/unsubscribe/%recipient.id%",
 	) // IMPORTANT: No To:-field recipients!
-	
+
 	// Set template to be applied to this message.
 	m.SetTemplate("my-template")
 
@@ -937,7 +938,7 @@ func SendMessageWithTemplate(domain, apiKey string) error {
 	time.Sleep(time.Second * 1)
 
 	// Create a new message with template
-	m := mg.NewMessage("Excited User <excited@example.com>", "Template example", "")
+	m := mailgun.NewMessage("Excited User <excited@example.com>", "Template example", "")
 	m.SetTemplate("my-template")
 
 	// Add recipients
diff --git a/mailgun.go b/mailgun.go
index af25967..c77616b 100644
--- a/mailgun.go
+++ b/mailgun.go
@@ -141,9 +141,11 @@ type Mailgun interface {
 	AddOverrideHeader(k string, v string)
 	GetCurlOutput() string
 
-	Send(ctx context.Context, m *Message) (string, string, error)
+	Send(ctx context.Context, m *Message) (mes string, id string, err error)
 	ReSend(ctx context.Context, id string, recipients ...string) (string, string, error)
+	// Deprecated: use func NewMessage instead of method.
 	NewMessage(from, subject, text string, to ...string) *Message
+	// Deprecated: use func NewMIMEMessage instead of method.
 	NewMIMEMessage(body io.ReadCloser, to ...string) *Message
 
 	ListBounces(opts *ListOptions) *BouncesIterator
diff --git a/messages.go b/messages.go
index 23a20f0..06ef7e8 100644
--- a/messages.go
+++ b/messages.go
@@ -19,7 +19,7 @@ const MaxNumberOfRecipients = 1000
 // MaxNumberOfTags represents the maximum number of tags that can be added for a message
 const MaxNumberOfTags = 3
 
-// Message structures contain both the message text and the envelop for an e-mail message.
+// Message structures contain both the message text and the envelope for an e-mail message.
 type Message struct {
 	to                []string
 	tags              []string
@@ -54,7 +54,6 @@ type Message struct {
 	skipVerification  bool
 
 	specific features
-	mg       Mailgun
 }
 
 type ReaderAttachment struct {
@@ -144,11 +143,13 @@ type TrackingOptions struct {
 }
 
 // features abstracts the common characteristics between regular and MIME messages.
-// addCC, addBCC, recipientCount, setHtml and setAMPHtml are invoked via the package-global AddCC, AddBCC,
-// RecipientCount, SetHtml and SetAMPHtml calls, as these functions are ignored for MIME messages.
+// addCC, addBCC, recipientCount, setHtml and setAMPHtml are invoked via the AddCC, AddBCC,
+// RecipientCount, SetHTML and SetAMPHtml calls, as these functions are ignored for MIME messages.
 // Send() invokes addValues to add message-type-specific MIME headers for the API call
-// to Mailgun.  isValid yeilds true if and only if the message is valid enough for sending
-// through the API.  Finally, endpoint() tells Send() which endpoint to use to submit the API call.
+// to Mailgun.
+// isValid yields true if and only if the message is valid enough for sending
+// through the API.
+// Finally, endpoint() tells Send() which endpoint to use to submit the API call.
 type features interface {
 	addCC(string)
 	addBCC(string)
@@ -163,20 +164,18 @@ type features interface {
 
 // NewMessage returns a new e-mail message with the simplest envelop needed to send.
 //
-// Unlike the global function,
-// this method supports arbitrary-sized recipient lists by
+// Supports arbitrary-sized recipient lists by
 // automatically sending mail in batches of up to MaxNumberOfRecipients.
 //
-// To support batch sending, you don't want to provide a fixed To: header at this point.
-// Pass nil as the to parameter to skip adding the To: header at this stage.
+// To support batch sending, do not provide `to` at this point.
 // You can do this explicitly, or implicitly, as follows:
 //
-//	// Note absence of To parameter(s)!
-//	m := mg.NewMessage("me@example.com", "Help save our planet", "Hello world!")
+//	// Note absence of `to` parameter(s)!
+//	m := NewMessage("me@example.com", "Help save our planet", "Hello world!")
 //
 // Note that you'll need to invoke the AddRecipientAndVariables or AddRecipient method
 // before sending, though.
-func (mg *MailgunImpl) NewMessage(from, subject, text string, to ...string) *Message {
+func NewMessage(from, subject, text string, to ...string) *Message {
 	return &Message{
 		specific: &plainMessage{
 			from:    from,
@@ -184,37 +183,47 @@ func (mg *MailgunImpl) NewMessage(from, subject, text string, to ...string) *Mes
 			text:    text,
 		},
 		to: to,
-		mg: mg,
 	}
 }
 
-// NewMIMEMessage creates a new MIME message.  These messages are largely canned;
+// Deprecated: use func NewMessage instead of method.
+//
+// TODO(v5): remove this method
+func (*MailgunImpl) NewMessage(from, subject, text string, to ...string) *Message {
+	return NewMessage(from, subject, text, to...)
+}
+
+// NewMIMEMessage creates a new MIME message. These messages are largely canned;
 // you do not need to invoke setters to set message-related headers.
 // However, you do still need to call setters for Mailgun-specific settings.
 //
-// Unlike the global function,
-// this method supports arbitrary-sized recipient lists by
+// Supports arbitrary-sized recipient lists by
 // automatically sending mail in batches of up to MaxNumberOfRecipients.
 //
-// To support batch sending, you don't want to provide a fixed To: header at this point.
-// Pass nil as the to parameter to skip adding the To: header at this stage.
+// To support batch sending, do not provide `to` at this point.
 // You can do this explicitly, or implicitly, as follows:
 //
-//	// Note absence of To parameter(s)!
-//	m := mg.NewMessage("me@example.com", "Help save our planet", "Hello world!")
+//	// Note absence of `to` parameter(s)!
+//	m := NewMIMEMessage(body)
 //
 // Note that you'll need to invoke the AddRecipientAndVariables or AddRecipient method
 // before sending, though.
-func (mg *MailgunImpl) NewMIMEMessage(body io.ReadCloser, to ...string) *Message {
+func NewMIMEMessage(body io.ReadCloser, to ...string) *Message {
 	return &Message{
 		specific: &mimeMessage{
 			body: body,
 		},
 		to: to,
-		mg: mg,
 	}
 }
 
+// Deprecated: use func NewMIMEMessage instead of method.
+//
+// TODO(v5): remove this method
+func (*MailgunImpl) NewMIMEMessage(body io.ReadCloser, to ...string) *Message {
+	return NewMIMEMessage(body, to...)
+}
+
 // AddReaderAttachment arranges to send a file along with the e-mail message.
 // File contents are read from a io.ReadCloser.
 // The filename parameter is the resulting filename of the attachment.
@@ -307,10 +316,6 @@ func (mm *mimeMessage) recipientCount() int {
 	return 10
 }
 
-func (m *Message) send(ctx context.Context) (string, string, error) {
-	return m.mg.Send(ctx, m)
-}
-
 // SetReplyTo sets the receiver who should receive replies
 func (m *Message) SetReplyTo(recipient string) {
 	m.AddHeader("Reply-To", recipient)
@@ -338,8 +343,15 @@ func (pm *plainMessage) addBCC(r string) {
 
 func (mm *mimeMessage) addBCC(_ string) {}
 
-// SetHtml is a helper. If you're sending a message that isn't already MIME encoded, SetHtml() will arrange to bundle
+// SetHTML is a helper. If you're sending a message that isn't already MIME encoded, SetHtml() will arrange to bundle
 // an HTML representation of your message in addition to your plain-text body.
+func (m *Message) SetHTML(html string) {
+	m.specific.setHtml(html)
+}
+
+// Deprecated: use SetHTML instead.
+//
+// TODO(v5): remove this method
 func (m *Message) SetHtml(html string) {
 	m.specific.setHtml(html)
 }
@@ -350,7 +362,7 @@ func (pm *plainMessage) setHtml(h string) {
 
 func (mm *mimeMessage) setHtml(_ string) {}
 
-// SetAMP is a helper. If you're sending a message that isn't already MIME encoded, SetAMP() will arrange to bundle
+// SetAMPHtml is a helper. If you're sending a message that isn't already MIME encoded, SetAMP() will arrange to bundle
 // an AMP-For-Email representation of your message in addition to your html & plain-text content.
 func (m *Message) SetAMPHtml(html string) {
 	m.specific.setAMPHtml(html)
@@ -422,6 +434,8 @@ func (m *Message) SetDeliveryTime(dt time.Time) {
 // Refer to the Mailgun documentation for more information.
 func (m *Message) SetSTOPeriod(stoPeriod string) error {
 	validPattern := `^([2-6][4-9]|[3-6][0-9]|7[0-2])h$`
+	// TODO(vtopc): regexp.Compile, which is called by regexp.MatchString, is a heave operation, move into global variable
+	// or just parse using time.ParseDuration().
 	match, err := regexp.MatchString(validPattern, stoPeriod)
 	if err != nil {
 		return err


Test patch:
diff --git a/attachments_test.go b/attachments_test.go
index 74d9d4e..bf137e0 100644
--- a/attachments_test.go
+++ b/attachments_test.go
@@ -30,7 +30,7 @@ func TestMultipleAttachments(t *testing.T) {
 
 	var ctx = context.Background()
 
-	m := mg.NewMessage("root@"+testDomain, "Subject", "Text Body", "attachment@"+testDomain)
+	m := mailgun.NewMessage("root@"+testDomain, "Subject", "Text Body", "attachment@"+testDomain)
 
 	// Add 2 attachments
 	m.AddAttachment(createAttachment(t))
diff --git a/events_test.go b/events_test.go
index ed655e9..1c3b1f2 100644
--- a/events_test.go
+++ b/events_test.go
@@ -86,7 +86,7 @@ func TestEventPoller(t *testing.T) {
 	}()
 
 	// Send an email
-	m := mg.NewMessage("root@"+testDomain, "Subject", "Text Body", "user@"+testDomain)
+	m := mailgun.NewMessage("root@"+testDomain, "Subject", "Text Body", "user@"+testDomain)
 	msg, id, err := mg.Send(ctx, m)
 	ensure.Nil(t, err)
 
@@ -126,7 +126,7 @@ func ExampleMailgunImpl_ListEvents() {
 	for it.Next(ctx, &page) {
 		for _, e := range page {
 			// You can access some fields via the interface
-			//fmt.Printf("Event: '%s' TimeStamp: '%s'\n", e.GetName(), e.GetTimestamp())
+			// fmt.Printf("Event: '%s' TimeStamp: '%s'\n", e.GetName(), e.GetTimestamp())
 
 			// and you can act upon each event by type
 			switch event := e.(type) {
diff --git a/examples_test.go b/examples_test.go
index 25c4132..ba440c9 100644
--- a/examples_test.go
+++ b/examples_test.go
@@ -4,7 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"log"
 	"net/http"
 	"os"
@@ -80,7 +80,7 @@ func ExampleMailgunImpl_Send_constructed() {
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
 
-	m := mg.NewMessage(
+	m := mailgun.NewMessage(
 		"Excited User <me@example.com>",
 		"Hello World",
 		"Testing some Mailgun Awesomeness!",
@@ -89,7 +89,7 @@ func ExampleMailgunImpl_Send_constructed() {
 	)
 	m.SetTracking(true)
 	m.SetDeliveryTime(time.Now().Add(24 * time.Hour))
-	m.SetHtml("<html><body><h1>Testing some Mailgun Awesomeness!!</h1></body></html>")
+	m.SetHTML("<html><body><h1>Testing some Mailgun Awesomeness!!</h1></body></html>")
 	_, id, err := mg.Send(ctx, m)
 	if err != nil {
 		log.Fatal(err)
@@ -112,7 +112,7 @@ Testing some Mailgun MIME awesomeness!
 	defer cancel()
 
 	mg := mailgun.NewMailgun("example.com", "my_api_key")
-	m := mg.NewMIMEMessage(ioutil.NopCloser(strings.NewReader(exampleMime)), "bargle.garf@example.com")
+	m := mailgun.NewMIMEMessage(io.NopCloser(strings.NewReader(exampleMime)), "bargle.garf@example.com")
 	_, id, err := mg.Send(ctx, m)
 	if err != nil {
 		log.Fatal(err)
diff --git a/messages_test.go b/messages_test.go
index 25e8896..b617e91 100644
--- a/messages_test.go
+++ b/messages_test.go
@@ -3,7 +3,7 @@ package mailgun_test
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"os"
@@ -58,7 +58,7 @@ func TestSendMGPlain(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
 		t.Log("TestSendPlain:MSG(" + msg + "),ID(" + id + ")")
@@ -76,7 +76,7 @@ func TestSendMGPlainWithTracking(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 		m.SetTracking(true)
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
@@ -95,7 +95,7 @@ func TestSendMGPlainAt(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 		m.SetDeliveryTime(time.Now().Add(5 * time.Minute))
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
@@ -114,7 +114,7 @@ func TestSendMGSTO(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 		m.SetSTOPeriod("24h")
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
@@ -133,8 +133,8 @@ func TestSendMGHtml(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
-		m.SetHtml(exampleHtml)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+		m.SetHTML(exampleHtml)
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
 		t.Log("TestSendHtml:MSG(" + msg + "),ID(" + id + ")")
@@ -152,8 +152,8 @@ func TestSendMGAMPHtml(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
-		m.SetHtml(exampleHtml)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+		m.SetHTML(exampleHtml)
 		m.SetAMPHtml(exampleAMPHtml)
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
@@ -172,7 +172,7 @@ func TestSendMGTracking(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText+"Tracking!\n", toUser)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText+"Tracking!\n", toUser)
 		m.SetTracking(false)
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
@@ -191,8 +191,8 @@ func TestSendMGTrackingClicksHtmlOnly(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
-		m.SetHtml(exampleHtml)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+		m.SetHTML(exampleHtml)
 		options := mailgun.TrackingOptions{
 			Tracking:       true,
 			TrackingClicks: "htmlonly",
@@ -216,7 +216,7 @@ func TestSendMGTag(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText+"Tags Galore!\n", toUser)
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText+"Tags Galore!\n", toUser)
 		m.AddTag("FooTag")
 		m.AddTag("BarTag")
 		m.AddTag("BlortTag")
@@ -237,7 +237,7 @@ func TestSendMGMIME(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMIMEMessage(ioutil.NopCloser(strings.NewReader(exampleMime)), toUser)
+		m := mailgun.NewMIMEMessage(io.NopCloser(strings.NewReader(exampleMime)), toUser)
 		msg, id, err := mg.Send(ctx, m)
 		ensure.Nil(t, err)
 		t.Log("TestSendMIME:MSG(" + msg + "),ID(" + id + ")")
@@ -251,14 +251,12 @@ func TestSendMGBatchFailRecipients(t *testing.T) {
 
 	spendMoney(t, func() {
 		toUser := os.Getenv("MG_EMAIL_TO")
-		mg, err := mailgun.NewMailgunFromEnv()
-		ensure.Nil(t, err)
 
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText+"Batch\n")
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText+"Batch\n")
 		for i := 0; i < mailgun.MaxNumberOfRecipients; i++ {
 			m.AddRecipient("") // We expect this to indicate a failure at the API
 		}
-		err = m.AddRecipientAndVariables(toUser, nil)
+		err := m.AddRecipientAndVariables(toUser, nil)
 		// In case of error the SDK didn't send the message,
 		// OR the API didn't check for empty To: headers.
 		ensure.NotNil(t, err)
@@ -276,7 +274,7 @@ func TestSendMGBatchRecipientVariables(t *testing.T) {
 		ensure.Nil(t, err)
 
 		ctx := context.Background()
-		m := mg.NewMessage(fromUser, exampleSubject, templateText)
+		m := mailgun.NewMessage(fromUser, exampleSubject, templateText)
 		err = m.AddRecipientAndVariables(toUser, map[string]interface{}{
 			"name":  "Joe Cool Example",
 			"table": 42,
@@ -311,7 +309,7 @@ func TestSendMGOffline(t *testing.T) {
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	msg, id, err := mg.Send(ctx, m)
 	ensure.Nil(t, err)
 	ensure.DeepEqual(t, msg, exampleMessage)
@@ -344,7 +342,7 @@ func TestSendMGSeparateDomain(t *testing.T) {
 	mg.SetAPIBase(srv.URL + "/v3")
 
 	ctx := context.Background()
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	m.AddDomain(signingDomain)
 
 	msg, id, err := mg.Send(ctx, m)
@@ -397,7 +395,7 @@ func TestSendMGMessageVariables(t *testing.T) {
 	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	m.AddVariable(exampleStrVarKey, exampleStrVarVal)
 	m.AddVariable(exampleBoolVarKey, false)
 	m.AddVariable(exampleMapVarKey, exampleMapVarVal)
@@ -410,9 +408,7 @@ func TestSendMGMessageVariables(t *testing.T) {
 }
 
 func TestAddRecipientsError(t *testing.T) {
-
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText)
 
 	for i := 0; i < 1000; i++ {
 		recipient := fmt.Sprintf("recipient_%d@example.com", i)
@@ -427,8 +423,7 @@ func TestAddRecipientsError(t *testing.T) {
 func TestAddRecipientAndVariablesError(t *testing.T) {
 	var err error
 
-	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText)
 
 	for i := 0; i < 1000; i++ {
 		recipient := fmt.Sprintf("recipient_%d@example.com", i)
@@ -467,7 +462,7 @@ func TestSendDomainError(t *testing.T) {
 		ctx := context.Background()
 		mg := mailgun.NewMailgun(c.domain, exampleAPIKey)
 		mg.SetAPIBase(srv.URL + "/v3")
-		m := mg.NewMessage(fromUser, exampleSubject, exampleText, "test@test.com")
+		m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, "test@test.com")
 
 		_, _, err := mg.Send(ctx, m)
 		if c.isValid {
@@ -493,7 +488,7 @@ func TestSendEOFError(t *testing.T) {
 	mg := mailgun.NewMailgun(exampleDomain, exampleAPIKey)
 	mg.SetAPIBase(srv.URL + "/v3")
 
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	_, _, err := mg.Send(context.Background(), m)
 	ensure.NotNil(t, err)
 	ensure.StringContains(t, err.Error(), "remote server prematurely closed connection: Post ")
@@ -518,19 +513,19 @@ func TestHasRecipient(t *testing.T) {
 	mg.SetAPIBase(srv.URL + "/v3")
 
 	// No recipient
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText)
 	_, _, err := mg.Send(context.Background(), m)
 	ensure.NotNil(t, err)
 	ensure.DeepEqual(t, err.Error(), "message not valid")
 
 	// Provided Bcc
-	m = mg.NewMessage(fromUser, exampleSubject, exampleText)
+	m = mailgun.NewMessage(fromUser, exampleSubject, exampleText)
 	m.AddBCC(recipient)
 	_, _, err = mg.Send(context.Background(), m)
 	ensure.Nil(t, err)
 
 	// Provided cc
-	m = mg.NewMessage(fromUser, exampleSubject, exampleText)
+	m = mailgun.NewMessage(fromUser, exampleSubject, exampleText)
 	m.AddCC(recipient)
 	_, _, err = mg.Send(context.Background(), m)
 	ensure.Nil(t, err)
@@ -592,7 +587,7 @@ func TestAddOverrideHeader(t *testing.T) {
 	mg.AddOverrideHeader("CustomHeader", "custom-value")
 	ctx := context.Background()
 
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	m.SetRequireTLS(true)
 	m.SetSkipVerification(true)
 
@@ -631,7 +626,7 @@ func TestOnBehalfOfSubaccount(t *testing.T) {
 	mg.SetOnBehalfOfSubaccount("mailgun.subaccount")
 	ctx := context.Background()
 
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	m.SetRequireTLS(true)
 	m.SetSkipVerification(true)
 
@@ -663,7 +658,7 @@ func TestCaptureCurlOutput(t *testing.T) {
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	msg, id, err := mg.Send(ctx, m)
 	ensure.Nil(t, err)
 	ensure.DeepEqual(t, msg, exampleMessage)
@@ -699,7 +694,7 @@ func TestSendTLSOptions(t *testing.T) {
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
-	m := mg.NewMessage(fromUser, exampleSubject, exampleText, toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, exampleText, toUser)
 	m.SetRequireTLS(true)
 	m.SetSkipVerification(true)
 
@@ -729,7 +724,7 @@ func TestSendTemplate(t *testing.T) {
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
-	m := mg.NewMessage(fromUser, exampleSubject, "", toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, "", toUser)
 	m.SetTemplate(templateName)
 
 	msg, id, err := mg.Send(ctx, m)
@@ -762,7 +757,7 @@ func TestSendTemplateOptions(t *testing.T) {
 	mg.SetAPIBase(srv.URL + "/v3")
 	ctx := context.Background()
 
-	m := mg.NewMessage(fromUser, exampleSubject, "", toUser)
+	m := mailgun.NewMessage(fromUser, exampleSubject, "", toUser)
 	m.SetTemplate(templateName)
 	m.SetTemplateRenderText(true)
 	m.SetTemplateVersion(templateVersionTag)
diff --git a/storage_test.go b/storage_test.go
index 1a0b1ad..e1d2263 100644
--- a/storage_test.go
+++ b/storage_test.go
@@ -3,11 +3,12 @@ package mailgun_test
 import (
 	"context"
 	"fmt"
+	"strings"
+	"testing"
+
 	"github.com/facebookgo/ensure"
 	"github.com/mailgun/mailgun-go/v4"
 	"github.com/mailgun/mailgun-go/v4/events"
-	"strings"
-	"testing"
 )
 
 func TestStorage(t *testing.T) {
@@ -16,7 +17,7 @@ func TestStorage(t *testing.T) {
 
 	var ctx = context.Background()
 
-	m := mg.NewMessage("root@"+testDomain, "Subject", "Text Body", "stored@"+testDomain)
+	m := mailgun.NewMessage("root@"+testDomain, "Subject", "Text Body", "stored@"+testDomain)
 	msg, id, err := mg.Send(ctx, m)
 	ensure.Nil(t, err)
 
diff --git a/tags_test.go b/tags_test.go
index 2c67f85..cae953b 100644
--- a/tags_test.go
+++ b/tags_test.go
@@ -19,7 +19,7 @@ const (
 func TestTags(t *testing.T) {
 	mg := mailgun.NewMailgun(testDomain, testKey)
 	mg.SetAPIBase(server.URL())
-	msg := mg.NewMessage(fromUser, exampleSubject, exampleText, "test@example.com")
+	msg := mailgun.NewMessage(fromUser, exampleSubject, exampleText, "test@example.com")
 	ensure.Nil(t, msg.AddTag("newsletter"))
 	ensure.Nil(t, msg.AddTag("homer"))
 	ensure.Nil(t, msg.AddTag("bart"))