129 lines
4.0 KiB
Go
129 lines
4.0 KiB
Go
package mailgun
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// Bounce aggregates data relating to undeliverable messages to a specific intended recipient,
|
|
// identified by Address.
|
|
// Code provides the SMTP error code causing the bounce,
|
|
// while Error provides a human readable reason why.
|
|
// CreatedAt provides the time at which Mailgun detected the bounce.
|
|
type Bounce struct {
|
|
CreatedAt string `json:"created_at"`
|
|
code interface{} `json:"code"`
|
|
Address string `json:"address"`
|
|
Error string `json:"error"`
|
|
}
|
|
|
|
type Paging struct {
|
|
First string `json:"first"`
|
|
Next string `json:"next"`
|
|
Previous string `json:"previous"`
|
|
Last string `json:"last"`
|
|
}
|
|
|
|
type bounceEnvelope struct {
|
|
Items []Bounce `json:"items"`
|
|
Paging Paging `json:"paging"`
|
|
}
|
|
|
|
// GetCreatedAt parses the textual, RFC-822 timestamp into a standard Go-compatible
|
|
// Time structure.
|
|
func (i Bounce) GetCreatedAt() (t time.Time, err error) {
|
|
return parseMailgunTime(i.CreatedAt)
|
|
}
|
|
|
|
// GetCode will return the bounce code for the message, regardless if it was
|
|
// returned as a string or as an integer. This method overcomes a protocol
|
|
// bug in the Mailgun API.
|
|
func (b Bounce) GetCode() (int, error) {
|
|
switch c := b.code.(type) {
|
|
case int:
|
|
return c, nil
|
|
case string:
|
|
return strconv.Atoi(c)
|
|
default:
|
|
return -1, strconv.ErrSyntax
|
|
}
|
|
}
|
|
|
|
// GetBounces returns a complete set of bounces logged against the sender's domain, if any.
|
|
// The results include the total number of bounces (regardless of skip or limit settings),
|
|
// and the slice of bounces specified, if successful.
|
|
// Note that the length of the slice may be smaller than the total number of bounces.
|
|
func (m *MailgunImpl) GetBounces(limit, skip int) (int, []Bounce, error) {
|
|
r := newHTTPRequest(generateApiUrl(m, bouncesEndpoint))
|
|
if limit != -1 {
|
|
r.addParameter("limit", strconv.Itoa(limit))
|
|
}
|
|
if skip != -1 {
|
|
r.addParameter("skip", strconv.Itoa(skip))
|
|
}
|
|
|
|
r.setClient(m.Client())
|
|
r.setBasicAuth(basicAuthUser, m.ApiKey())
|
|
|
|
var response bounceEnvelope
|
|
err := getResponseFromJSON(r, &response)
|
|
if err != nil {
|
|
return -1, nil, err
|
|
}
|
|
|
|
return len(response.Items), response.Items, nil
|
|
}
|
|
|
|
// GetSingleBounce retrieves a single bounce record, if any exist, for the given recipient address.
|
|
func (m *MailgunImpl) GetSingleBounce(address string) (Bounce, error) {
|
|
r := newHTTPRequest(generateApiUrl(m, bouncesEndpoint) + "/" + address)
|
|
r.setClient(m.Client())
|
|
r.setBasicAuth(basicAuthUser, m.ApiKey())
|
|
|
|
var response Bounce
|
|
err := getResponseFromJSON(r, &response)
|
|
return response, err
|
|
}
|
|
|
|
// AddBounce files a bounce report.
|
|
// Address identifies the intended recipient of the message that bounced.
|
|
// Code corresponds to the numeric response given by the e-mail server which rejected the message.
|
|
// Error providees the corresponding human readable reason for the problem.
|
|
// For example,
|
|
// here's how the these two fields relate.
|
|
// Suppose the SMTP server responds with an error, as below.
|
|
// Then, . . .
|
|
//
|
|
// 550 Requested action not taken: mailbox unavailable
|
|
// \___/\_______________________________________________/
|
|
// | |
|
|
// `-- Code `-- Error
|
|
//
|
|
// Note that both code and error exist as strings, even though
|
|
// code will report as a number.
|
|
func (m *MailgunImpl) AddBounce(address, code, error string) error {
|
|
r := newHTTPRequest(generateApiUrl(m, bouncesEndpoint))
|
|
r.setClient(m.Client())
|
|
r.setBasicAuth(basicAuthUser, m.ApiKey())
|
|
|
|
payload := newUrlEncodedPayload()
|
|
payload.addValue("address", address)
|
|
if code != "" {
|
|
payload.addValue("code", code)
|
|
}
|
|
if error != "" {
|
|
payload.addValue("error", error)
|
|
}
|
|
_, err := makePostRequest(r, payload)
|
|
return err
|
|
}
|
|
|
|
// DeleteBounce removes all bounces associted with the provided e-mail address.
|
|
func (m *MailgunImpl) DeleteBounce(address string) error {
|
|
r := newHTTPRequest(generateApiUrl(m, bouncesEndpoint) + "/" + address)
|
|
r.setClient(m.Client())
|
|
r.setBasicAuth(basicAuthUser, m.ApiKey())
|
|
_, err := makeDeleteRequest(r)
|
|
return err
|
|
}
|