diff --git a/suppressions.go b/suppressions.go new file mode 100644 index 0000000..bc502ce --- /dev/null +++ b/suppressions.go @@ -0,0 +1,110 @@ +package postmark + +import ( + "fmt" + "net/url" +) + +// SuppressionReasonType - The reason type of suppression +type SuppressionReasonType string + +// OriginType - The reason type of origin +type OriginType string + +const ( + HardBounceReason SuppressionReasonType = "HardBounce" + SpamComplaintReason SuppressionReasonType = "SpamComplaint" + ManualSuppressionReason SuppressionReasonType = "ManualSuppression" + RecipientOrigin OriginType = "Recipient" + CustomerOrigin OriginType = "Customer" + AdminOrigin OriginType = "Admin" +) + +// SuppressionEmail - Suppression email entry +type SuppressionEmail struct { + // EmailAddress - The email address of suppression. + EmailAddress string + // SuppressionReason - The reason of suppression. + SuppressionReason SuppressionReasonType + // Origin - Possible options: Recipient, Customer, Admin. + Origin OriginType + // CreatedAt - Timestamp. + CreatedAt string +} + +// suppressionsResponse - A message received from the Postmark server +type suppressionsResponse struct { + // Suppressions - The slice of suppression email address. + Suppressions []SuppressionEmail +} + +// EmailAddress - Email address to delete +type EmailAddress struct { + EmailAddress string `json:",omitempty"` +} + +// DeleteSuppressions - A payload of email address to delete +type DeleteSuppressions struct { + // Suppressions - The slice of email address to delete. + Suppressions []EmailAddress `json:",omitempty"` +} + +// deleteSuppressionsResponse - A message received from the Postmark server +type deleteSuppressionsResponse struct { + // Suppressions - The slice of deleted email status and reason. + Suppressions []SuppressionDelete +} + +// SuppressionDelete - Suppression email deleted +type SuppressionDelete struct { + EmailAddress string + Status string + Message *string +} + +// GetSuppressionEmails fetches a email addresses in the list of suppression dump on the server +// It returns a SuppressionEmails slice, and any error that occurred +// https://postmarkapp.com/developer/api/suppressions-api#suppression-dump +func (client *Client) GetSuppressionEmails(streamID string, options map[string]interface{}) ([]SuppressionEmail, error) { + values := &url.Values{} + for k, v := range options { + values.Add(k, fmt.Sprintf("%v", v)) + } + + path := fmt.Sprintf("message-streams/%s/suppressions/dump", streamID) + if len(options) != 0 { + path = fmt.Sprintf("%s?%s", path, values.Encode()) + } + + res := suppressionsResponse{} + err := client.doRequest(parameters{ + Method: "GET", + Path: path, + TokenType: server_token, + }, &res) + return res.Suppressions, err +} + +// DeleteSuppressionEmails delete email addresses in the list of suppression dump on the server +// Noet: SpamComplaint and ManualSuppression with Origin: Customer cannot be deleted +// It return a SuppressionDelete slice, and any error that occurred +// https://postmarkapp.com/developer/api/suppressions-api#delete-a-suppression +func (client *Client) DeleteSuppressionEmails(streamID string, delete []string) ([]SuppressionDelete, error) { + emailAddresses := make([]EmailAddress, 0, 8) + for _, address := range delete { + emailAddresses = append(emailAddresses, EmailAddress{ + EmailAddress: address, + }) + } + + res := deleteSuppressionsResponse{} + err := client.doRequest(parameters{ + Method: "POST", + Path: fmt.Sprintf("message-streams/%s/suppressions/delete", streamID), + Payload: DeleteSuppressions{ + Suppressions: emailAddresses, + }, + TokenType: server_token, + }, &res) + return res.Suppressions, err +} diff --git a/suppressions_test.go b/suppressions_test.go new file mode 100644 index 0000000..588cac6 --- /dev/null +++ b/suppressions_test.go @@ -0,0 +1,119 @@ +package postmark + +import ( + "net/http" + "testing" + + "goji.io/pat" +) + +func TestGetSuppressionEmails(t *testing.T) { + responseJSON := `{ + "Suppressions":[ + { + "EmailAddress":"address@wildbit.com", + "SuppressionReason":"ManualSuppression", + "Origin": "Recipient", + "CreatedAt":"2019-12-10T08:58:33-05:00" + }, + { + "EmailAddress":"bounce.address@wildbit.com", + "SuppressionReason":"HardBounce", + "Origin": "Recipient", + "CreatedAt":"2019-12-11T08:58:33-05:00" + }, + { + "EmailAddress":"spam.complaint.address@wildbit.com", + "SuppressionReason":"SpamComplaint", + "Origin": "Recipient", + "CreatedAt":"2019-12-12T08:58:33-05:00" + } + ] + }` + + tMux.HandleFunc(pat.Get("/message-streams/:StreamID/suppressions/dump"), func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte(responseJSON)) + }) + + res, err := client.GetSuppressionEmails("outbound", nil) + + if err != nil { + t.Fatalf("GetSuppressionEmails: %s", err.Error()) + } + + if len(res) != 3 { + t.Fatalf("GetSuppressionEmails: wrong number of suppression (%d)", len(res)) + } + + if res[0].EmailAddress != "address@wildbit.com" { + t.Fatalf("GetSuppressionEmails: wrong suppression email address: %s", res[0].EmailAddress) + } + + responseJSON = `{ + "Suppressions":[ + { + "EmailAddress":"address@wildbit.com", + "SuppressionReason":"ManualSuppression", + "Origin": "Recipient", + "CreatedAt":"2019-12-10T08:58:33-05:00" + } + ] + }` + + tMux.HandleFunc(pat.Get("/message-streams/:StreamID/suppressions/dump"), func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte(responseJSON)) + }) + + res, err = client.GetSuppressionEmails("outbound", map[string]interface{}{ + "emailaddress": "address@wildbit.com", + "fromdate": "2019-12-10", + "todate": "2019-12-11", + "suppressionreason": HardBounceReason, + "origin": RecipientOrigin, + }) + + if len(res) != 1 { + t.Fatalf("GetSuppressionEmails: wrong number of suppression (%d)", len(res)) + } + + if res[0].EmailAddress != "address@wildbit.com" { + t.Fatalf("GetSuppressionEmails: wrong suppression email address: %s", res[0].EmailAddress) + } + +} + +func TestDeleteSuppressionEmails(t *testing.T) { + responseJSON := `{ + "Suppressions":[ + { + "EmailAddress":"good.address@wildbit.com", + "Status":"Deleted", + "Message": null + }, + { + "EmailAddress":"not.suppressed@wildbit.com", + "Status":"Deleted", + "Message": null + }, + { + "EmailAddress":"spammy.address@wildbit.com", + "Status":"Failed", + "Message": "You do not have the required authority to change this suppression." + } + ] + }` + + tMux.HandleFunc(pat.Post("/message-streams/:StreamID/suppressions/delete"), func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte(responseJSON)) + }) + + res, err := client.DeleteSuppressionEmails("outbound", []string{"good.address@wildbit.com", "not.suppressed@wildbit.com", "spammy.address@wildbit.com"}) + + if err != nil { + t.Fatalf("DeleteSuppressionEmails: %s", err.Error()) + } + + if len(res) != 3 { + t.Fatalf("DeleteSuppressionEmails: wrong number of suppression (%d)", len(res)) + } +}