Skip to content

Commit df42160

Browse files
authored
Merge pull request #184 from thrawn01/thrawn/develop
Added support for sending with template using the new template API
2 parents 33eaa4c + 850df88 commit df42160

8 files changed

Lines changed: 273 additions & 16 deletions

File tree

CHANGELOG

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [3.4.0] - 2019-04-23
8+
### Added
9+
* Added `Message.SetTemplate()` to allow sending with the body of a template.
10+
### Changes
11+
* Changed signature of `CreateDomain()` moved password into `CreateDomainOptions`
12+
713
## [3.3.2] - 2019-03-28
814
### Changes
915
* Uncommented DeliveryStatus.Code and change it to an integer (See #175)

domains.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ func (mg *MailgunImpl) VerifyDomain(ctx context.Context, domain string) (string,
254254

255255
// Optional parameters when creating a domain
256256
type CreateDomainOptions struct {
257+
Password string
257258
SpamAction SpamAction
258259
Wildcard bool
259260
ForceDKIMAuthority bool
@@ -267,14 +268,13 @@ type CreateDomainOptions struct {
267268
// The spamAction domain must be one of Delete, Tag, or Disabled.
268269
// The wildcard parameter instructs Mailgun to treat all subdomains of this domain uniformly if true,
269270
// and as different domains if false.
270-
func (mg *MailgunImpl) CreateDomain(ctx context.Context, name string, password string, opts *CreateDomainOptions) (DomainResponse, error) {
271+
func (mg *MailgunImpl) CreateDomain(ctx context.Context, name string, opts *CreateDomainOptions) (DomainResponse, error) {
271272
r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint))
272273
r.setClient(mg.Client())
273274
r.setBasicAuth(basicAuthUser, mg.APIKey())
274275

275276
payload := newUrlEncodedPayload()
276277
payload.addValue("name", name)
277-
payload.addValue("smtp_password", password)
278278

279279
if opts != nil {
280280
if opts.SpamAction != "" {
@@ -292,6 +292,9 @@ func (mg *MailgunImpl) CreateDomain(ctx context.Context, name string, password s
292292
if len(opts.IPS) != 0 {
293293
payload.addValue("ips", strings.Join(opts.IPS, ","))
294294
}
295+
if len(opts.Password) != 0 {
296+
payload.addValue("smtp_password", opts.Password)
297+
}
295298
}
296299
var resp DomainResponse
297300
err := postResponseFromJSON(ctx, r, payload, &resp)

domains_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ func TestAddDeleteDomain(t *testing.T) {
7575
ctx := context.Background()
7676

7777
// First, we need to add the domain.
78-
_, err := mg.CreateDomain(ctx, "mx.mailgun.test", "supersecret",
79-
&mailgun.CreateDomainOptions{SpamAction: mailgun.SpamActionTag})
78+
_, err := mg.CreateDomain(ctx, "mx.mailgun.test",
79+
&mailgun.CreateDomainOptions{SpamAction: mailgun.SpamActionTag, Password: "supersecret"})
8080
ensure.Nil(t, err)
8181

8282
// Next, we delete it.

examples/examples.go

Lines changed: 192 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package main
1+
package examples
22

33
import (
44
"context"
@@ -33,7 +33,8 @@ func AddDomain(domain, apiKey string) (mailgun.DomainResponse, error) {
3333
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
3434
defer cancel()
3535

36-
return mg.CreateDomain(ctx, "example.com", "super_secret", &mailgun.CreateDomainOptions{
36+
return mg.CreateDomain(ctx, "example.com", &mailgun.CreateDomainOptions{
37+
Password: "super_secret",
3738
SpamAction: mailgun.SpamActionTag,
3839
Wildcard: false,
3940
})
@@ -142,7 +143,8 @@ func CreateDomain(domain, apiKey string) (mailgun.DomainResponse, error) {
142143
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
143144
defer cancel()
144145

145-
return mg.CreateDomain(ctx, "example.com", "super_secret", &mailgun.CreateDomainOptions{
146+
return mg.CreateDomain(ctx, "example.com", &mailgun.CreateDomainOptions{
147+
Password: "super_secret",
146148
SpamAction: mailgun.SpamActionTag,
147149
Wildcard: false,
148150
})
@@ -894,3 +896,190 @@ func VerifyWebhookSignature(domain, apiKey, timestamp, token, signature string)
894896
Signature: signature,
895897
})
896898
}
899+
900+
func SendMessageWithTemplate(domain, apiKey string) error {
901+
mg := mailgun.NewMailgun(domain, apiKey)
902+
var err error
903+
904+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
905+
defer cancel()
906+
907+
// Create a new template
908+
err = mg.CreateTemplate(ctx, &mailgun.Template{
909+
Name: "my-template",
910+
Version: mailgun.TemplateVersion{
911+
Template: `'<div class="entry"> <h1>{{.title}}</h1> <div class="body"> {{.body}} </div> </div>'`,
912+
Engine: mailgun.TemplateEngineGo,
913+
Tag: "v1",
914+
},
915+
})
916+
if err != nil {
917+
return err
918+
}
919+
920+
// Give time for template to show up in the system.
921+
time.Sleep(time.Second * 1)
922+
923+
// Create a new message with template
924+
m := mg.NewMessage("Excited User <excited@example.com>", "Template example", "")
925+
m.SetTemplate("my-template")
926+
927+
// Add recipients
928+
m.AddRecipient("bob@example.com")
929+
m.AddRecipient("alice@example.com")
930+
931+
// Add the variables to be used by the template
932+
m.AddVariable("title", "Hello Templates")
933+
m.AddVariable("body", "Body of the message")
934+
935+
_, id, err := mg.Send(ctx, m)
936+
fmt.Printf("Queued: %s", id)
937+
return err
938+
}
939+
940+
func CreateTemplate(domain, apiKey string) error {
941+
mg := mailgun.NewMailgun(domain, apiKey)
942+
943+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
944+
defer cancel()
945+
946+
return mg.CreateTemplate(ctx, &mailgun.Template{
947+
Name: "my-template",
948+
Version: mailgun.TemplateVersion{
949+
Template: `'<div class="entry"> <h1>{{.title}}</h1> <div class="body"> {{.body}} </div> </div>'`,
950+
Engine: mailgun.TemplateEngineGo,
951+
Tag: "v1",
952+
},
953+
})
954+
}
955+
956+
func DeleteTemplate(domain, apiKey string) error {
957+
mg := mailgun.NewMailgun(domain, apiKey)
958+
959+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
960+
defer cancel()
961+
962+
return mg.DeleteTemplate(ctx, "my-template")
963+
}
964+
965+
func UpdateTemplate(domain, apiKey string) error {
966+
mg := mailgun.NewMailgun(domain, apiKey)
967+
968+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
969+
defer cancel()
970+
971+
return mg.UpdateTemplate(ctx, &mailgun.Template{
972+
Name: "my-template",
973+
Description: "Add a description to the template",
974+
})
975+
}
976+
977+
func GetTemplate(domain, apiKey string) (mailgun.Template, error) {
978+
mg := mailgun.NewMailgun(domain, apiKey)
979+
980+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
981+
defer cancel()
982+
983+
return mg.GetTemplate(ctx, "my-template")
984+
}
985+
986+
func ListActiveTemplates(domain, apiKey string) ([]mailgun.Template, error) {
987+
mg := mailgun.NewMailgun(domain, apiKey)
988+
it := mg.ListTemplates(&mailgun.ListTemplateOptions{Active: true})
989+
990+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
991+
defer cancel()
992+
993+
var page, result []mailgun.Template
994+
for it.Next(ctx, &page) {
995+
result = append(result, page...)
996+
}
997+
998+
if it.Err() != nil {
999+
return nil, it.Err()
1000+
}
1001+
return result, nil
1002+
}
1003+
1004+
func ListTemplates(domain, apiKey string) ([]mailgun.Template, error) {
1005+
mg := mailgun.NewMailgun(domain, apiKey)
1006+
it := mg.ListTemplates(nil)
1007+
1008+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
1009+
defer cancel()
1010+
1011+
var page, result []mailgun.Template
1012+
for it.Next(ctx, &page) {
1013+
result = append(result, page...)
1014+
}
1015+
1016+
if it.Err() != nil {
1017+
return nil, it.Err()
1018+
}
1019+
return result, nil
1020+
}
1021+
1022+
func AddTemplateVersion(domain, apiKey string) error {
1023+
mg := mailgun.NewMailgun(domain, apiKey)
1024+
1025+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
1026+
defer cancel()
1027+
1028+
return mg.AddTemplateVersion(ctx, "my-template", &mailgun.TemplateVersion{
1029+
Template: `'<div class="entry"> <h1>{{.title}}</h1> <div class="body"> {{.body}} </div> </div>'`,
1030+
Engine: mailgun.TemplateEngineGo,
1031+
Tag: "v2",
1032+
Active: true,
1033+
})
1034+
}
1035+
1036+
func DeleteTemplateVersion(domain, apiKey string) error {
1037+
mg := mailgun.NewMailgun(domain, apiKey)
1038+
1039+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
1040+
defer cancel()
1041+
1042+
// Delete the template version tagged as 'v2'
1043+
return mg.DeleteTemplateVersion(ctx, "my-template", "v2")
1044+
}
1045+
1046+
func GetTemplateVersion(domain, apiKey string) (mailgun.TemplateVersion, error) {
1047+
mg := mailgun.NewMailgun(domain, apiKey)
1048+
1049+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
1050+
defer cancel()
1051+
1052+
// Get the template version tagged as 'v2'
1053+
return mg.GetTemplateVersion(ctx, "my-template", "v2")
1054+
}
1055+
1056+
func UpdateTemplateVersion(domain, apiKey string) error {
1057+
mg := mailgun.NewMailgun(domain, apiKey)
1058+
1059+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
1060+
defer cancel()
1061+
1062+
return mg.UpdateTemplateVersion(ctx, "my-template", &mailgun.TemplateVersion{
1063+
Comment: "Add a comment to the template and make it 'active'",
1064+
Tag: "v2",
1065+
Active: true,
1066+
})
1067+
}
1068+
1069+
func ListTemplateVersions(domain, apiKey string) ([]mailgun.TemplateVersion, error) {
1070+
mg := mailgun.NewMailgun(domain, apiKey)
1071+
it := mg.ListTemplateVersions("my-template", nil)
1072+
1073+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
1074+
defer cancel()
1075+
1076+
var page, result []mailgun.TemplateVersion
1077+
for it.Next(ctx, &page) {
1078+
result = append(result, page...)
1079+
}
1080+
1081+
if it.Err() != nil {
1082+
return nil, it.Err()
1083+
}
1084+
return result, nil
1085+
}

mailgun.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ type Mailgun interface {
141141

142142
ListDomains(opts *ListOptions) *DomainsIterator
143143
GetDomain(ctx context.Context, domain string) (DomainResponse, error)
144-
CreateDomain(ctx context.Context, name string, pass string, opts *CreateDomainOptions) (DomainResponse, error)
144+
CreateDomain(ctx context.Context, name string, opts *CreateDomainOptions) (DomainResponse, error)
145145
DeleteDomain(ctx context.Context, name string) error
146146
VerifyDomain(ctx context.Context, name string) (string, error)
147147
UpdateDomainConnection(ctx context.Context, domain string, dc DomainConnection) error
@@ -219,7 +219,7 @@ type Mailgun interface {
219219
GetTemplate(ctx context.Context, id string) (Template, error)
220220
UpdateTemplate(ctx context.Context, template *Template) error
221221
DeleteTemplate(ctx context.Context, id string) error
222-
ListTemplates(opts *ListOptions) *TemplatesIterator
222+
ListTemplates(opts *ListTemplateOptions) *TemplatesIterator
223223

224224
AddTemplateVersion(ctx context.Context, templateId string, version *TemplateVersion) error
225225
GetTemplateVersion(ctx context.Context, templateId, versionId string) (TemplateVersion, error)

messages.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,13 @@ type StoredMessageRaw struct {
110110
// although from, subject, and text are set when the message is created with
111111
// NewMessage.
112112
type plainMessage struct {
113-
from string
114-
cc []string
115-
bcc []string
116-
subject string
117-
text string
118-
html string
113+
from string
114+
cc []string
115+
bcc []string
116+
subject string
117+
text string
118+
html string
119+
template string
119120
}
120121

121122
// mimeMessage contains fields relevant to pre-packaged MIME messages.
@@ -142,6 +143,7 @@ type features interface {
142143
isValid() bool
143144
endpoint() string
144145
recipientCount() int
146+
setTemplate(string)
145147
}
146148

147149
// NewMessage returns a new e-mail message with the simplest envelop needed to send.
@@ -343,6 +345,18 @@ func (m *Message) AddTag(tag ...string) error {
343345
return nil
344346
}
345347

348+
// SetTemplate sets the name of a template stored via the template API.
349+
// See https://documentation.mailgun.com/en/latest/user_manual.html#templating
350+
func (m *Message) SetTemplate(t string) {
351+
m.specific.setTemplate(t)
352+
}
353+
354+
func (pm *plainMessage) setTemplate(t string) {
355+
pm.template = t
356+
}
357+
358+
func (mm *mimeMessage) setTemplate(t string) {}
359+
346360
// This feature is deprecated for new software.
347361
func (m *Message) AddCampaign(campaign string) {
348362
m.campaigns = append(m.campaigns, campaign)
@@ -585,6 +599,9 @@ func (pm *plainMessage) addValues(p *formDataPayload) {
585599
if pm.html != "" {
586600
p.addValue("html", pm.html)
587601
}
602+
if pm.template != "" {
603+
p.addValue("template", pm.template)
604+
}
588605
}
589606

590607
func (mm *mimeMessage) addValues(p *formDataPayload) {
@@ -653,6 +670,11 @@ func (pm *plainMessage) isValid() bool {
653670
return false
654671
}
655672

673+
if pm.template != "" {
674+
// pm.text or pm.html not needed if template is supplied
675+
return true
676+
}
677+
656678
if pm.text == "" && pm.html == "" {
657679
return false
658680
}

messages_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,32 @@ func TestSendTLSOptions(t *testing.T) {
479479
ensure.DeepEqual(t, msg, exampleMessage)
480480
ensure.DeepEqual(t, id, exampleID)
481481
}
482+
483+
func TestSendTemplate(t *testing.T) {
484+
const (
485+
exampleDomain = "testDomain"
486+
exampleAPIKey = "testAPIKey"
487+
toUser = "test@test.com"
488+
exampleMessage = "Queue. Thank you"
489+
exampleID = "<20111114174239.25659.5817@samples.mailgun.org>"
490+
templateName = "my-template"
491+
)
492+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
493+
ensure.DeepEqual(t, req.FormValue("template"), templateName)
494+
rsp := fmt.Sprintf(`{"message":"%s", "id":"%s"}`, exampleMessage, exampleID)
495+
fmt.Fprint(w, rsp)
496+
}))
497+
defer srv.Close()
498+
499+
mg := NewMailgun(exampleDomain, exampleAPIKey)
500+
mg.SetAPIBase(srv.URL)
501+
ctx := context.Background()
502+
503+
m := mg.NewMessage(fromUser, exampleSubject, "", toUser)
504+
m.SetTemplate(templateName)
505+
506+
msg, id, err := mg.Send(ctx, m)
507+
ensure.Nil(t, err)
508+
ensure.DeepEqual(t, msg, exampleMessage)
509+
ensure.DeepEqual(t, id, exampleID)
510+
}

0 commit comments

Comments
 (0)