Skip to content

Commit 5d96a0d

Browse files
authored
implementing domain keys API calls (#450)
Closes #436
1 parent fba8f44 commit 5d96a0d

9 files changed

Lines changed: 624 additions & 6 deletions

File tree

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,7 @@ func main() {
373373
```
374374

375375
The official mailgun documentation includes examples using this library. Go
376-
[here](https://documentation.mailgun.com/docs/mailgun/api-reference/)
377-
and click on the "Go" button at the top of the page.
376+
[here](https://documentation.mailgun.com/docs/mailgun/sdk/go_sdk).
378377

379378
## EU Region
380379
European customers will need to change the default API Base to access your domains

domain_keys.go

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,340 @@ package mailgun
22

33
import (
44
"context"
5+
"fmt"
6+
"strconv"
7+
8+
"github.com/mailgun/mailgun-go/v5/mtypes"
59
)
610

11+
type ListAllDomainsKeysOptions struct {
12+
Limit int
13+
}
14+
15+
type CreateDomainKeyOptions struct {
16+
Bits int
17+
PEM string
18+
}
19+
20+
type AllDomainsKeysIterator struct {
21+
mtypes.ListAllDomainsKeysResponse
22+
23+
limit int
24+
mg Mailgun
25+
url string
26+
err error
27+
}
28+
29+
type DomainKeysIterator struct {
30+
mtypes.ListDomainKeysResponse
31+
32+
mg Mailgun
33+
url string
34+
err error
35+
}
36+
37+
// ListAllDomainsKeys retrieves a set of domain keys from Mailgun.
38+
func (mg *Client) ListAllDomainsKeys(opts *ListAllDomainsKeysOptions) *AllDomainsKeysIterator {
39+
var limit int
40+
if opts != nil {
41+
limit = opts.Limit
42+
}
43+
44+
if limit == 0 {
45+
limit = 100
46+
}
47+
return &AllDomainsKeysIterator{
48+
mg: mg,
49+
url: generateApiUrl(mg, 1, dkimEndpoint),
50+
ListAllDomainsKeysResponse: mtypes.ListAllDomainsKeysResponse{TotalCount: -1},
51+
limit: limit,
52+
}
53+
}
54+
55+
// Err if an error occurred during iteration `Err()` will return non nil
56+
func (ri *AllDomainsKeysIterator) Err() error {
57+
return ri.err
58+
}
59+
60+
// Next retrieves the next page of items from the api. Returns false when there
61+
// are no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
62+
// the error
63+
func (ri *AllDomainsKeysIterator) Next(ctx context.Context, items *[]mtypes.DomainKey) bool {
64+
if ri.err != nil {
65+
return false
66+
}
67+
68+
ri.err = ri.fetch(ctx, ri.Paging.Next, ri.limit)
69+
if ri.err != nil {
70+
return false
71+
}
72+
73+
cpy := make([]mtypes.DomainKey, len(ri.Items))
74+
copy(cpy, ri.Items)
75+
*items = cpy
76+
return len(ri.Items) != 0
77+
}
78+
79+
// First retrieves the first page of items from the api. Returns false if there
80+
// was an error. It also sets the iterator object to the first page.
81+
// Use `.Err()` to retrieve the error.
82+
func (ri *AllDomainsKeysIterator) First(ctx context.Context, items *[]mtypes.DomainKey) bool {
83+
if ri.err != nil {
84+
return false
85+
}
86+
ri.err = ri.fetch(ctx, ri.Paging.First, ri.limit)
87+
if ri.err != nil {
88+
return false
89+
}
90+
cpy := make([]mtypes.DomainKey, len(ri.Items))
91+
copy(cpy, ri.Items)
92+
*items = cpy
93+
return true
94+
}
95+
96+
// Last retrieves the last page of items from the api.
97+
// Calling Last() is invalid unless you first call First() or Next()
98+
// Returns false if there was an error. It also sets the iterator object
99+
// to the last page. Use `.Err()` to retrieve the error.
100+
func (ri *AllDomainsKeysIterator) Last(ctx context.Context, items *[]mtypes.DomainKey) bool {
101+
if ri.err != nil {
102+
return false
103+
}
104+
105+
if ri.TotalCount == -1 {
106+
return false
107+
}
108+
109+
ri.err = ri.fetch(ctx, ri.Paging.Last, ri.limit)
110+
if ri.err != nil {
111+
return false
112+
}
113+
cpy := make([]mtypes.DomainKey, len(ri.Items))
114+
copy(cpy, ri.Items)
115+
*items = cpy
116+
return true
117+
}
118+
119+
// Previous retrieves the previous page of items from the api. Returns false when there
120+
// are no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
121+
// the error if any
122+
func (ri *AllDomainsKeysIterator) Previous(ctx context.Context, items *[]mtypes.DomainKey) bool {
123+
if ri.err != nil {
124+
return false
125+
}
126+
127+
if ri.TotalCount == -1 {
128+
return false
129+
}
130+
131+
ri.err = ri.fetch(ctx, ri.Paging.Previous, ri.limit)
132+
if ri.err != nil {
133+
return false
134+
}
135+
cpy := make([]mtypes.DomainKey, len(ri.Items))
136+
copy(cpy, ri.Items)
137+
*items = cpy
138+
139+
return len(ri.Items) != 0
140+
}
141+
142+
func (ri *AllDomainsKeysIterator) fetch(ctx context.Context, pageUrl string, limit int) error {
143+
ri.Items = nil
144+
uri := ri.url
145+
if pageUrl != "" {
146+
uri = pageUrl
147+
}
148+
r := newHTTPRequest(uri)
149+
150+
r.setBasicAuth(basicAuthUser, ri.mg.APIKey())
151+
r.setClient(ri.mg.HTTPClient())
152+
153+
if limit != 0 {
154+
r.addParameter("limit", strconv.Itoa(limit))
155+
}
156+
157+
return getResponseFromJSON(ctx, r, &ri.ListAllDomainsKeysResponse)
158+
}
159+
160+
// CreateDomainKey creates a domain key for the given domain
161+
func (mg *Client) CreateDomainKey(ctx context.Context, domain, dkimSelector string, opts *CreateDomainKeyOptions) (mtypes.DomainKey, error) {
162+
r := newHTTPRequest(generateApiUrl(mg, 1, dkimEndpoint))
163+
r.setClient(mg.HTTPClient())
164+
r.setBasicAuth(basicAuthUser, mg.APIKey())
165+
166+
payload := newUrlEncodedPayload()
167+
payload.addValue("signing_domain", domain)
168+
payload.addValue("selector", dkimSelector)
169+
170+
if opts.Bits != 0 {
171+
payload.addValue("bits", strconv.Itoa(opts.Bits))
172+
}
173+
174+
if opts.PEM != "" {
175+
payload.addValue("pem", opts.PEM)
176+
}
177+
178+
var resp mtypes.DomainKey
179+
err := postResponseFromJSON(ctx, r, payload, &resp)
180+
return resp, err
181+
}
182+
183+
// DeleteDomainKey deletes a domain key from the given domain
184+
func (mg *Client) DeleteDomainKey(ctx context.Context, domain, dkimSelector string) error {
185+
r := newHTTPRequest(generateApiUrl(mg, 1, dkimEndpoint))
186+
r.setClient(mg.HTTPClient())
187+
r.setBasicAuth(basicAuthUser, mg.APIKey())
188+
189+
r.addParameter("signing_domain", domain)
190+
r.addParameter("selector", dkimSelector)
191+
192+
_, err := makeDeleteRequest(ctx, r)
193+
return err
194+
}
195+
196+
// ActivateDomainKey deactivates a domain key for the given domain
197+
func (mg *Client) ActivateDomainKey(ctx context.Context, domain, dkimSelector string) error {
198+
uri := generateActivateDomainKeyApiUrl(domainsEndpoint, domain, dkimSelector)
199+
200+
r := newHTTPRequest(generateApiUrl(mg, 4, uri))
201+
r.setClient(mg.HTTPClient())
202+
r.setBasicAuth(basicAuthUser, mg.APIKey())
203+
204+
_, err := makePutRequest(ctx, r, newUrlEncodedPayload())
205+
return err
206+
}
207+
208+
// ListDomainKeys retrieves a set of domain keys from Mailgun.
209+
func (mg *Client) ListDomainKeys(domain string) *DomainKeysIterator {
210+
uri := generateListDomainKeysApiUrl(domainsEndpoint, domain)
211+
212+
return &DomainKeysIterator{
213+
mg: mg,
214+
url: generateApiUrl(mg, 4, uri),
215+
ListDomainKeysResponse: mtypes.ListDomainKeysResponse{},
216+
}
217+
}
218+
219+
// Err if an error occurred during iteration `Err()` will return non nil
220+
func (ri *DomainKeysIterator) Err() error {
221+
return ri.err
222+
}
223+
224+
// Next retrieves the next page of items from the api. Returns false when there
225+
// are no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
226+
// the error
227+
func (ri *DomainKeysIterator) Next(ctx context.Context, items *[]mtypes.DomainKey) bool {
228+
if ri.err != nil {
229+
return false
230+
}
231+
232+
ri.err = ri.fetch(ctx, ri.Paging.Next)
233+
if ri.err != nil {
234+
return false
235+
}
236+
237+
cpy := make([]mtypes.DomainKey, len(ri.Items))
238+
copy(cpy, ri.Items)
239+
*items = cpy
240+
return len(ri.Items) != 0
241+
}
242+
243+
// First retrieves the first page of items from the api. Returns false if there
244+
// was an error. It also sets the iterator object to the first page.
245+
// Use `.Err()` to retrieve the error.
246+
func (ri *DomainKeysIterator) First(ctx context.Context, items *[]mtypes.DomainKey) bool {
247+
if ri.err != nil {
248+
return false
249+
}
250+
ri.err = ri.fetch(ctx, ri.Paging.First)
251+
if ri.err != nil {
252+
return false
253+
}
254+
cpy := make([]mtypes.DomainKey, len(ri.Items))
255+
copy(cpy, ri.Items)
256+
*items = cpy
257+
return true
258+
}
259+
260+
// Last retrieves the last page of items from the api.
261+
// Calling Last() is invalid unless you first call First() or Next()
262+
// Returns false if there was an error. It also sets the iterator object
263+
// to the last page. Use `.Err()` to retrieve the error.
264+
func (ri *DomainKeysIterator) Last(ctx context.Context, items *[]mtypes.DomainKey) bool {
265+
if ri.err != nil {
266+
return false
267+
}
268+
269+
ri.err = ri.fetch(ctx, ri.Paging.Last)
270+
if ri.err != nil {
271+
return false
272+
}
273+
cpy := make([]mtypes.DomainKey, len(ri.Items))
274+
copy(cpy, ri.Items)
275+
*items = cpy
276+
return true
277+
}
278+
279+
// Previous retrieves the previous page of items from the api. Returns false when there
280+
// are no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
281+
// the error if any
282+
func (ri *DomainKeysIterator) Previous(ctx context.Context, items *[]mtypes.DomainKey) bool {
283+
if ri.err != nil {
284+
return false
285+
}
286+
287+
ri.err = ri.fetch(ctx, ri.Paging.Previous)
288+
if ri.err != nil {
289+
return false
290+
}
291+
cpy := make([]mtypes.DomainKey, len(ri.Items))
292+
copy(cpy, ri.Items)
293+
*items = cpy
294+
295+
return len(ri.Items) != 0
296+
}
297+
298+
func (ri *DomainKeysIterator) fetch(ctx context.Context, pageUrl string) error {
299+
ri.Items = nil
300+
uri := ri.url
301+
if pageUrl != "" {
302+
uri = pageUrl
303+
}
304+
r := newHTTPRequest(uri)
305+
306+
r.setBasicAuth(basicAuthUser, ri.mg.APIKey())
307+
r.setClient(ri.mg.HTTPClient())
308+
309+
return getResponseFromJSON(ctx, r, &ri.ListDomainKeysResponse)
310+
}
311+
312+
// DeactivateDomainKey deactivates a domain key for the given domain
313+
func (mg *Client) DeactivateDomainKey(ctx context.Context, domain, dkimSelector string) error {
314+
uri := generateDeactivateDomainKeyApiUrl(domainsEndpoint, domain, dkimSelector)
315+
316+
r := newHTTPRequest(generateApiUrl(mg, 4, uri))
317+
r.setClient(mg.HTTPClient())
318+
r.setBasicAuth(basicAuthUser, mg.APIKey())
319+
320+
_, err := makePutRequest(ctx, r, newUrlEncodedPayload())
321+
return err
322+
}
323+
324+
func (mg *Client) UpdateDomainDkimAuthority(ctx context.Context, domain string, self bool) (mtypes.UpdateDomainDkimAuthorityResponse, error) {
325+
r := newHTTPRequest(generateApiUrl(mg, 3, domainsEndpoint) + "/" + domain + "/dkim_authority")
326+
r.setClient(mg.HTTPClient())
327+
r.setBasicAuth(basicAuthUser, mg.APIKey())
328+
329+
payload := newUrlEncodedPayload()
330+
payload.addValue("self", boolToString(self))
331+
332+
var resp mtypes.UpdateDomainDkimAuthorityResponse
333+
334+
err := putResponseFromJSON(ctx, r, payload, &resp)
335+
336+
return resp, err
337+
}
338+
7339
// UpdateDomainDkimSelector updates the DKIM selector for a domain
8340
func (mg *Client) UpdateDomainDkimSelector(ctx context.Context, domain, dkimSelector string) error {
9341
r := newHTTPRequest(generateApiUrl(mg, 3, domainsEndpoint) + "/" + domain + "/dkim_selector")
@@ -15,3 +347,18 @@ func (mg *Client) UpdateDomainDkimSelector(ctx context.Context, domain, dkimSele
15347
_, err := makePutRequest(ctx, r, payload)
16348
return err
17349
}
350+
351+
// generateActivateDomainKeyApiUrl renders a URL fragment relevant for deactivating a domain key
352+
func generateActivateDomainKeyApiUrl(endpoint, domain, dkimSelector string) string {
353+
return fmt.Sprintf("%s/%s/keys/%s/activate", endpoint, domain, dkimSelector)
354+
}
355+
356+
// generateListDomainKeysApiUrl renders a URL fragment relevant for listing a domain's keys
357+
func generateListDomainKeysApiUrl(endpoint, domain string) string {
358+
return fmt.Sprintf("%s/%s/keys", endpoint, domain)
359+
}
360+
361+
// generateDeactivateDomainKeyApiUrl renders a URL fragment relevant for deactivating a domain key
362+
func generateDeactivateDomainKeyApiUrl(endpoint, domain, dkimSelector string) string {
363+
return fmt.Sprintf("%s/%s/keys/%s/deactivate", endpoint, domain, dkimSelector)
364+
}

0 commit comments

Comments
 (0)