Skip to content

Commit cc0ffdc

Browse files
author
Chris Wilson
committed
Adds code to filter message events
1 parent 379140f commit cc0ffdc

File tree

4 files changed

+375
-14
lines changed

4 files changed

+375
-14
lines changed

apps/sparkpost-samples-app/src/main/java/com/sparkpost/samples/MessageEventSearchSample.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
import java.io.IOException;
55
import java.util.List;
66
import java.util.Map;
7-
import java.util.Set;
87

98
import org.apache.log4j.Level;
109
import org.apache.log4j.Logger;
1110

1211
import com.sparkpost.Client;
1312
import com.sparkpost.exception.SparkPostErrorServerResponseException;
1413
import com.sparkpost.exception.SparkPostException;
14+
import com.sparkpost.model.MessageEventsQueryBuilder;
1515
import com.sparkpost.model.responses.MessageEventsResponse;
1616
import com.sparkpost.resources.ResourceMessageEvents;
1717
import com.sparkpost.sdk.samples.helpers.SparkPostBaseApp;
@@ -41,14 +41,20 @@ private void doSearch() throws SparkPostException, IOException, InterruptedExcep
4141
MessageEventsResponse response = null;
4242
do {
4343
if (response == null) {
44-
response = ResourceMessageEvents.searchMessageEvents(connection, 10);
44+
45+
// Message events can be filtered with the Message Event Query Builder
46+
MessageEventsQueryBuilder query = null;
47+
//query = new MessageEventsQueryBuilder();
48+
//query.addMessageId("Message ID Here");
49+
50+
response = ResourceMessageEvents.searchMessageEvents(connection, 10, query);
4551
} else {
4652
try {
4753
response = ResourceMessageEvents.nextMessageEvents(connection, response);
4854
} catch (SparkPostErrorServerResponseException e) {
4955
if (e.getResponseCode() == 429) {
5056
// We hit rate limit. Retry request again after a delay
51-
System.out.println("Hit the rate limit!!! Will retry after delay...");
57+
System.out.println("Hit the rate limit!!! Continue after delay...");
5258
Thread.sleep(30000);
5359
continue;
5460
}
@@ -69,18 +75,16 @@ private void doSearch() throws SparkPostException, IOException, InterruptedExcep
6975
List<Map<String, Object>> results = response.getResults();
7076
for (Map<String, Object> result : results) {
7177
System.out.println("\nResult (" + result.get("type") + ")");
72-
Set<String> keySet = result.keySet();
73-
for (String key : keySet) {
74-
// Print out result
75-
System.out.println("\t" + key + " = " + result.get(key));
78+
for (Map.Entry<String, Object> entry : result.entrySet()) {
79+
System.out.println("\t" + entry.getKey() + "=" + entry.getValue());
7680
}
7781
}
7882
}
7983
System.out.println("Total Count: " + response.getTotalCount());
8084
System.out.println("Links: " + response.getLinks());
8185
System.out.println("Has Next Page: " + response.hasNext());
8286

83-
} while (response != null && response.hasNext());
87+
} while (response.hasNext());
8488
}
8589

8690
}
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
2+
package com.sparkpost.model;
3+
4+
import java.util.HashSet;
5+
import java.util.Set;
6+
7+
import org.apache.commons.lang3.StringUtils;
8+
9+
import com.sparkpost.resources.Endpoint;
10+
11+
public class MessageEventsQueryBuilder {
12+
13+
private Set<BounceClass> bounceClasses = new HashSet<BounceClass>();
14+
private Set<String> campaignIds = new HashSet<String>();
15+
private Set<EventType> events = new HashSet<EventType>();
16+
private Set<String> friendlyFroms = new HashSet<String>();
17+
private String fromDateTime;
18+
private String toDateTime;
19+
private Set<String> messageIds = new HashSet<String>();
20+
private String reason;
21+
private Set<String> recipients = new HashSet<String>();
22+
private Set<String> subaccounts = new HashSet<String>();
23+
private Set<String> templateIds = new HashSet<String>();
24+
private String timezone;
25+
private Set<String> transmissionIds = new HashSet<String>();
26+
27+
/**
28+
* Bounce Classification Codes:
29+
* https://www.sparkpost.com/docs/deliverability/bounce-classification-codes
30+
*/
31+
public enum BounceClass {
32+
UNDERTERMINED(1, "Undetermined", "The response text could not be identified.", "Undetermined"),
33+
INVALID_RECIPIENT(10, "Invalid Recipient", "The recipient is invalid.", "Hard"),
34+
SOFT_BOUNCE(20, "Soft Bounce", "The message soft bounced.", "Soft"),
35+
DNS_FAILURE(21, "DNS Failure", "The message bounced due to a DNS failure.", "Soft"),
36+
MAILBOX_FULL(22, "Mailbox Full", "The message bounced due to the remote mailbox being over quota.", "Soft"),
37+
TOO_LARGE(23, "Too Large", "The message bounced because it was too large for the recipient.", "Soft"),
38+
TIMEOUT(24, "Timeout", "The message timed out.", "Soft"),
39+
ADMIN_FAILURE(25, "Admin Failure", "The message was failed by SparkPost’s configured policies.", "Admin"),
40+
NO_RCPT(30, "Generic Bounce", "No RCPT No recipient could be determined for the message.", "Hard"),
41+
GENERIC_BOUCNE(40, "Generic Bounce", "The message failed for unspecified reasons.", "Soft"),
42+
MAIL_BLOCK(50, "Mail Block", "The message was blocked by the receiver.", "Block"),
43+
SPAM_BLOCK(51, "Spam Block", "The message was blocked by the receiver as coming from a known spam source.", "Block"),
44+
SPAM_CONTENT(52, "Spam Content", "The message was blocked by the receiver as spam.", "Block"),
45+
PROHIBITED_ATTACHMENT(53, "Prohibited Attachment", "The message was blocked by the receiver because it contained an attachment.", "Block"),
46+
RELAYING_DENIED(54, "Relaying Denied", "The message was blocked by the receiver because relaying is not allowed.", "Block"),
47+
AUTO_REPLY(60, "Auto-Reply", "The message is an auto-reply/vacation mail.", "Soft"),
48+
TRANSIENT_FAILURE(70, "Transient Failure", "Message transmission has been temporarily delayed.", "Soft"),
49+
SUBSCRIBE(80, "Subscribe", "The message is a subscribe request.", "Admin"),
50+
UNSUBSCRIBE(90, "Unsubscribe", "The message is an unsubscribe request.", "Hard"),
51+
CHALLENGE_RESPONSE(100, "Challenge-Response", "The message is a challenge-response probe.", "Soft");
52+
53+
private final int classification;
54+
55+
private final String bounceName;
56+
57+
private final String description;
58+
59+
private final String category;
60+
61+
private BounceClass(int classification, String bounceName, String description, String category) {
62+
this.classification = classification;
63+
this.bounceName = bounceName;
64+
this.description = description;
65+
this.category = category;
66+
}
67+
68+
public int classification() {
69+
return this.classification;
70+
}
71+
72+
public String bounceName() {
73+
return this.bounceName;
74+
}
75+
76+
public String description() {
77+
return this.description;
78+
}
79+
80+
public String getCategory() {
81+
return this.category;
82+
}
83+
84+
@Override
85+
public String toString() {
86+
return "" + this.classification;
87+
}
88+
89+
}
90+
91+
public enum EventType {
92+
DELIVERY("delivery"),
93+
INJECTION("injection"),
94+
BOUNCE_DELAY("bounce,delay"),
95+
POLICY_REJECTION("policy_rejection"),
96+
OUT_OF_BAND("out_of_band"),
97+
OPEN_CLICK("open,click"),
98+
GENERATION_FAILURE("generation_failure"),
99+
GENERATION_REJECTION("generation_rejection"),
100+
SPAM_COMPLAINT("spam_complaint"),
101+
LIST_UNSUBSCRIBE("list_unsubscribe"),
102+
LINK_UNSUBSCRIBE("link_unsubscribe");
103+
104+
private final String eventType;
105+
106+
private EventType(String eventType) {
107+
this.eventType = eventType;
108+
}
109+
110+
public String eventType() {
111+
return this.eventType;
112+
}
113+
114+
@Override
115+
public String toString() {
116+
return this.eventType;
117+
}
118+
119+
}
120+
121+
/**
122+
* bounce_classes - delimited list of bounce classification codes to search.
123+
* See Bounce Classification Codes: https://www.sparkpost.com/docs/deliverability/bounce-classification-codes
124+
**/
125+
public void addBounceClass(BounceClass bounceClass) {
126+
this.bounceClasses.add(bounceClass);
127+
}
128+
129+
/**
130+
* campaign_ids - delimited list of campaign ID’s to search (i.e. the campaign id used during creation of a transmission).
131+
* Notes: Not available for sms_status type.
132+
**/
133+
public void addCampaignId(String cid) {
134+
this.campaignIds.add(cid);
135+
}
136+
137+
/**
138+
* events - delimited list of event types to search. Defaults to all event types.
139+
* Example:
140+
* delivery,injection,bounce,delay,policy_rejection,out_of_band,open,click,generation_failure,generation_rejection,spam_complaint,list_unsubscribe,link_unsubscribe
141+
**/
142+
public void addEventType(EventType type) {
143+
this.events.add(type);
144+
}
145+
146+
/**
147+
* friendly_froms - delimited list of friendly from emails to search.
148+
* Notes: Not available for sms_status type.
149+
* Example: [email protected]
150+
**/
151+
public void addFriendlyFrom(String from) {
152+
this.friendlyFroms.add(from);
153+
}
154+
155+
/**
156+
* From Datetime in format of YYYY-MM-DDTHH:MM.
157+
* Default: 24 hours ago
158+
* Example: 2014-07-20T08:00
159+
**/
160+
public void setFromDateTime(String dateTime) {
161+
this.fromDateTime = dateTime;
162+
}
163+
164+
public void setToDateTime(String dateTime) {
165+
this.toDateTime = dateTime;
166+
}
167+
168+
/**
169+
* message_ids - delimited list of message ID’s to search.
170+
* Example: 0e0d94b7-9085-4e3c-ab30-e3f2cd9c273e
171+
**/
172+
public void addMessageId(String messageId) {
173+
this.messageIds.add(messageId);
174+
}
175+
176+
/**
177+
* reason - Bounce/failure/rejection reason that will be matched using a wildcard (e.g., %reason%).
178+
* Example: bounce
179+
**/
180+
public void setReason(String reason) {
181+
this.reason = reason;
182+
}
183+
184+
/**
185+
* recipients - delimited list of recipients to search.
186+
* Example: [email protected]
187+
**/
188+
public void addRecipient(String recipient) {
189+
this.recipients.add(recipient);
190+
}
191+
192+
/**
193+
* subaccounts - delimited list of subaccount ID’s to search.
194+
* Example: 101
195+
**/
196+
public void addSubAccount(String subaccount) {
197+
this.subaccounts.add(subaccount);
198+
}
199+
200+
/**
201+
* template_ids - delimited list of template ID’s to search.
202+
* Example: templ-1234
203+
**/
204+
public void addTemplateId(String tid) {
205+
this.templateIds.add(tid);
206+
}
207+
208+
/**
209+
* timezone - Standard timezone identification string.
210+
* Default: UTC
211+
* Example: America/New_York
212+
**/
213+
public void setTimezone(String timeZone) {
214+
this.timezone = timeZone;
215+
}
216+
217+
/**
218+
* transmission_ids - delimited list of transmission ID’s to search (i.e. id generated during creation of a transmission).
219+
* Example: 65832150921904138
220+
**/
221+
public void addTransmissionId(String tid) {
222+
this.transmissionIds.add(tid);
223+
}
224+
225+
public void buildQuery(Endpoint endpoint) {
226+
if (this.bounceClasses.size() > 0) {
227+
endpoint.addParam("bounce_classes", StringUtils.join(this.bounceClasses, ","));
228+
}
229+
230+
if (this.campaignIds.size() > 0) {
231+
endpoint.addParam("campaign_ids", StringUtils.join(this.campaignIds, ','));
232+
}
233+
234+
if (this.events.size() > 0) {
235+
endpoint.addParam("events", StringUtils.join(this.events, ','));
236+
}
237+
238+
if (this.friendlyFroms.size() > 0) {
239+
endpoint.addParam("friendly_froms", StringUtils.join(this.friendlyFroms, ','));
240+
}
241+
242+
if (StringUtils.isNotEmpty(this.fromDateTime)) {
243+
endpoint.addParam("from", this.fromDateTime);
244+
}
245+
246+
if (StringUtils.isNotEmpty(this.toDateTime)) {
247+
endpoint.addParam("to", this.toDateTime);
248+
}
249+
250+
if (this.messageIds.size() > 0) {
251+
endpoint.addParam("message_ids", StringUtils.join(this.messageIds, ','));
252+
}
253+
254+
if (StringUtils.isNotEmpty(this.reason)) {
255+
endpoint.addParam("reason", this.reason);
256+
}
257+
258+
if (this.recipients.size() > 0) {
259+
endpoint.addParam("recipients", StringUtils.join(this.recipients, ','));
260+
}
261+
262+
if (this.subaccounts.size() > 0) {
263+
endpoint.addParam("subaccounts", StringUtils.join(this.subaccounts, ','));
264+
}
265+
266+
if (this.templateIds.size() > 0) {
267+
endpoint.addParam("template_ids", StringUtils.join(this.templateIds, ','));
268+
}
269+
270+
if (StringUtils.isNotEmpty(this.timezone)) {
271+
endpoint.addParam("timezone", this.timezone);
272+
}
273+
274+
if (this.transmissionIds.size() > 0) {
275+
endpoint.addParam("transmission_ids", StringUtils.join(this.transmissionIds, ','));
276+
}
277+
}
278+
279+
}

libs/sparkpost-lib/src/main/java/com/sparkpost/resources/ResourceMessageEvents.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.net.URISyntaxException;
66

77
import com.sparkpost.exception.SparkPostException;
8+
import com.sparkpost.model.MessageEventsQueryBuilder;
89
import com.sparkpost.model.responses.MessageEventsResponse;
910
import com.sparkpost.model.responses.Response;
1011
import com.sparkpost.transport.IRestConnection;
@@ -18,16 +19,27 @@
1819
public class ResourceMessageEvents {
1920

2021
public static MessageEventsResponse searchMessageEvents(IRestConnection conn) throws SparkPostException {
21-
Endpoint ep = new Endpoint("message-events");
22-
Response response = conn.get(ep);
23-
24-
MessageEventsResponse messageResponse = MessageEventsResponse.decode(response, MessageEventsResponse.class);
25-
return messageResponse;
22+
return ResourceMessageEvents.searchMessageEvents(conn, 0, null);
2623
}
2724

2825
public static MessageEventsResponse searchMessageEvents(IRestConnection conn, int perPage) throws SparkPostException {
26+
return ResourceMessageEvents.searchMessageEvents(conn, perPage, null);
27+
}
28+
29+
public static MessageEventsResponse searchMessageEvents(IRestConnection conn, MessageEventsQueryBuilder queryBuilder) throws SparkPostException {
30+
return ResourceMessageEvents.searchMessageEvents(conn, 0, queryBuilder);
31+
}
32+
33+
public static MessageEventsResponse searchMessageEvents(IRestConnection conn, int perPage, MessageEventsQueryBuilder queryBuilder)
34+
throws SparkPostException {
2935
Endpoint ep = new Endpoint("message-events");
30-
ep.addParam("per_page", perPage);
36+
if (queryBuilder != null) {
37+
queryBuilder.buildQuery(ep);
38+
}
39+
40+
if (perPage > 0) {
41+
ep.addParam("per_page", perPage);
42+
}
3143
Response response = conn.get(ep);
3244

3345
MessageEventsResponse messageResponse = MessageEventsResponse.decode(response, MessageEventsResponse.class);

0 commit comments

Comments
 (0)