Skip to content

Commit 859b51e

Browse files
authored
Merge pull request #48 from mailtrap/stats-api
Add Stats API
2 parents 1136e25 + 0c315b1 commit 859b51e

20 files changed

Lines changed: 617 additions & 28 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ You can find the [Mailtrap Java API reference](https://mailtrap.github.io/mailtr
342342
- [Batch](examples/java/io/mailtrap/examples/sending/BatchExample.java)
343343
- [Sending Domains](examples/java/io/mailtrap/examples/sendingdomains/SendingDomainsExample.java)
344344
- [Suppressions](examples/java/io/mailtrap/examples/suppressions/SuppressionsExample.java)
345+
- [Stats](examples/java/io/mailtrap/examples/sending/StatsExample.java)
345346

346347
### Email Testing API
347348

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.mailtrap.examples.sending;
2+
3+
import io.mailtrap.api.stats.StatsFilter;
4+
import io.mailtrap.config.MailtrapConfig;
5+
import io.mailtrap.factory.MailtrapClientFactory;
6+
7+
public class StatsExample {
8+
9+
private static final String TOKEN = "<YOUR MAILTRAP TOKEN>";
10+
private static final long ACCOUNT_ID = 1L;
11+
12+
// Set these to the desired date range (format: YYYY-MM-DD)
13+
private static final String START_DATE = "<START_DATE>";
14+
private static final String END_DATE = "<END_DATE>";
15+
16+
public static void main(String[] args) {
17+
final var config = new MailtrapConfig.Builder()
18+
.token(TOKEN)
19+
.build();
20+
21+
final var client = MailtrapClientFactory.createMailtrapClient(config);
22+
23+
final var filter = StatsFilter.builder()
24+
.startDate(START_DATE)
25+
.endDate(END_DATE)
26+
.build();
27+
28+
System.out.println("=== Aggregated Stats ===");
29+
System.out.println(client.sendingApi().stats().getStats(ACCOUNT_ID, filter));
30+
31+
System.out.println("\n=== Stats by Domains ===");
32+
System.out.println(client.sendingApi().stats().byDomain(ACCOUNT_ID, filter));
33+
34+
System.out.println("\n=== Stats by Categories ===");
35+
System.out.println(client.sendingApi().stats().byCategory(ACCOUNT_ID, filter));
36+
37+
System.out.println("\n=== Stats by Email Service Providers ===");
38+
System.out.println(client.sendingApi().stats().byEmailServiceProvider(ACCOUNT_ID, filter));
39+
40+
System.out.println("\n=== Stats by Date ===");
41+
System.out.println(client.sendingApi().stats().byDate(ACCOUNT_ID, filter));
42+
}
43+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.mailtrap.api.stats;
2+
3+
import io.mailtrap.model.response.stats.SendingStatGroupResponse;
4+
import io.mailtrap.model.response.stats.SendingStatsResponse;
5+
6+
import java.util.List;
7+
8+
/**
9+
* Interface representing the Mailtrap API for interaction with sending statistics
10+
*/
11+
public interface Stats {
12+
13+
/**
14+
* Get aggregated sending stats
15+
*
16+
* @param accountId unique account ID
17+
* @param filter stats filter parameters
18+
* @return aggregated sending statistics
19+
*/
20+
SendingStatsResponse getStats(long accountId, StatsFilter filter);
21+
22+
/**
23+
* Get sending stats grouped by domains
24+
*
25+
* @param accountId unique account ID
26+
* @param filter stats filter parameters
27+
* @return list of sending statistics grouped by domain
28+
*/
29+
List<SendingStatGroupResponse> byDomain(long accountId, StatsFilter filter);
30+
31+
/**
32+
* Get sending stats grouped by categories
33+
*
34+
* @param accountId unique account ID
35+
* @param filter stats filter parameters
36+
* @return list of sending statistics grouped by category
37+
*/
38+
List<SendingStatGroupResponse> byCategory(long accountId, StatsFilter filter);
39+
40+
/**
41+
* Get sending stats grouped by email service providers
42+
*
43+
* @param accountId unique account ID
44+
* @param filter stats filter parameters
45+
* @return list of sending statistics grouped by email service provider
46+
*/
47+
List<SendingStatGroupResponse> byEmailServiceProvider(long accountId, StatsFilter filter);
48+
49+
/**
50+
* Get sending stats grouped by date
51+
*
52+
* @param accountId unique account ID
53+
* @param filter stats filter parameters
54+
* @return list of sending statistics grouped by date
55+
*/
56+
List<SendingStatGroupResponse> byDate(long accountId, StatsFilter filter);
57+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.mailtrap.api.stats;
2+
3+
import io.mailtrap.model.SendingStream;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
import java.util.List;
10+
11+
@Data
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Builder
15+
public class StatsFilter {
16+
private String startDate;
17+
private String endDate;
18+
private List<Long> sendingDomainIds;
19+
private List<SendingStream> sendingStreams;
20+
private List<String> categories;
21+
private List<String> emailServiceProviders;
22+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package io.mailtrap.api.stats;
2+
3+
import io.mailtrap.Constants;
4+
import io.mailtrap.api.apiresource.ApiResource;
5+
import io.mailtrap.config.MailtrapConfig;
6+
import io.mailtrap.http.RequestData;
7+
import io.mailtrap.model.response.stats.SendingStatGroupResponse;
8+
import io.mailtrap.model.response.stats.SendingStatsResponse;
9+
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Optional;
13+
14+
import static io.mailtrap.http.RequestData.entry;
15+
16+
public class StatsImpl extends ApiResource implements Stats {
17+
18+
public StatsImpl(final MailtrapConfig config) {
19+
super(config);
20+
this.apiHost = Constants.GENERAL_HOST;
21+
}
22+
23+
@Override
24+
public SendingStatsResponse getStats(final long accountId, final StatsFilter filter) {
25+
return httpClient.get(
26+
buildUrl(accountId, ""),
27+
new RequestData(buildStatsQueryParams(filter)),
28+
SendingStatsResponse.class
29+
);
30+
}
31+
32+
@Override
33+
public List<SendingStatGroupResponse> byDomain(final long accountId, final StatsFilter filter) {
34+
return httpClient.getList(
35+
buildUrl(accountId, "/domains"),
36+
new RequestData(buildStatsQueryParams(filter)),
37+
SendingStatGroupResponse.class
38+
);
39+
}
40+
41+
@Override
42+
public List<SendingStatGroupResponse> byCategory(final long accountId, final StatsFilter filter) {
43+
return httpClient.getList(
44+
buildUrl(accountId, "/categories"),
45+
new RequestData(buildStatsQueryParams(filter)),
46+
SendingStatGroupResponse.class
47+
);
48+
}
49+
50+
@Override
51+
public List<SendingStatGroupResponse> byEmailServiceProvider(final long accountId, final StatsFilter filter) {
52+
return httpClient.getList(
53+
buildUrl(accountId, "/email_service_providers"),
54+
new RequestData(buildStatsQueryParams(filter)),
55+
SendingStatGroupResponse.class
56+
);
57+
}
58+
59+
@Override
60+
public List<SendingStatGroupResponse> byDate(final long accountId, final StatsFilter filter) {
61+
return httpClient.getList(
62+
buildUrl(accountId, "/date"),
63+
new RequestData(buildStatsQueryParams(filter)),
64+
SendingStatGroupResponse.class
65+
);
66+
}
67+
68+
private String buildUrl(final long accountId, final String suffix) {
69+
return String.format(apiHost + "/api/accounts/%d/stats%s", accountId, suffix);
70+
}
71+
72+
private Map<String, ? extends Optional<?>> buildStatsQueryParams(final StatsFilter filter) {
73+
if (filter == null) {
74+
throw new IllegalArgumentException("filter must not be null");
75+
}
76+
if (filter.getStartDate() == null || filter.getStartDate().trim().isEmpty()) {
77+
throw new IllegalArgumentException("startDate must not be null or empty");
78+
}
79+
if (filter.getEndDate() == null || filter.getEndDate().trim().isEmpty()) {
80+
throw new IllegalArgumentException("endDate must not be null or empty");
81+
}
82+
83+
return RequestData.buildQueryParams(
84+
entry("start_date", Optional.ofNullable(filter.getStartDate())),
85+
entry("end_date", Optional.ofNullable(filter.getEndDate())),
86+
entry("sending_domain_ids[]", Optional.ofNullable(filter.getSendingDomainIds())),
87+
entry("sending_streams[]", Optional.ofNullable(filter.getSendingStreams())),
88+
entry("categories[]", Optional.ofNullable(filter.getCategories())),
89+
entry("email_service_providers[]", Optional.ofNullable(filter.getEmailServiceProviders()))
90+
);
91+
}
92+
}

src/main/java/io/mailtrap/client/api/MailtrapEmailSendingApi.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.mailtrap.api.sendingdomains.SendingDomains;
44
import io.mailtrap.api.sendingemails.SendingEmails;
5+
import io.mailtrap.api.stats.Stats;
56
import io.mailtrap.api.suppressions.Suppressions;
67
import lombok.Getter;
78
import lombok.RequiredArgsConstructor;
@@ -17,4 +18,5 @@ public class MailtrapEmailSendingApi {
1718
private final SendingEmails emails;
1819
private final SendingDomains domains;
1920
private final Suppressions suppressions;
21+
private final Stats stats;
2022
}

src/main/java/io/mailtrap/factory/MailtrapClientFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.mailtrap.api.projects.ProjectsImpl;
2020
import io.mailtrap.api.sendingdomains.SendingDomainsImpl;
2121
import io.mailtrap.api.sendingemails.SendingEmailsImpl;
22+
import io.mailtrap.api.stats.StatsImpl;
2223
import io.mailtrap.api.suppressions.SuppressionsImpl;
2324
import io.mailtrap.api.testingemails.TestingEmailsImpl;
2425
import io.mailtrap.client.MailtrapClient;
@@ -95,8 +96,9 @@ private static MailtrapEmailSendingApi createSendingApi(final MailtrapConfig con
9596
final var emails = new SendingEmailsImpl(config, VALIDATOR);
9697
final var domains = new SendingDomainsImpl(config);
9798
final var suppressions = new SuppressionsImpl(config);
99+
final var stats = new StatsImpl(config);
98100

99-
return new MailtrapEmailSendingApi(emails, domains, suppressions);
101+
return new MailtrapEmailSendingApi(emails, domains, suppressions, stats);
100102
}
101103

102104
private static MailtrapEmailTestingApi createTestingApi(final MailtrapConfig config) {

src/main/java/io/mailtrap/http/CustomHttpClient.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import io.mailtrap.http.impl.DefaultMailtrapHttpClient;
88
import io.mailtrap.model.AbstractModel;
99

10+
import java.net.URLEncoder;
1011
import java.net.http.HttpClient;
12+
import java.nio.charset.StandardCharsets;
1113
import java.util.*;
1214
import java.util.stream.Collectors;
1315
import java.util.stream.Stream;
@@ -121,9 +123,9 @@ default String appendUrlParams(String url, Map<String, ? extends Optional<?>> ur
121123
return collection.stream()
122124
.filter(Objects::nonNull)
123125
.filter(v -> !v.toString().isBlank())
124-
.map(v -> entry.getKey() + "=" + v);
126+
.map(v -> entry.getKey() + "=" + URLEncoder.encode(v.toString(), StandardCharsets.UTF_8));
125127
} else {
126-
return Stream.of(entry.getKey() + "=" + value);
128+
return Stream.of(entry.getKey() + "=" + URLEncoder.encode(value.toString(), StandardCharsets.UTF_8));
127129
}
128130
})
129131
.collect(Collectors.joining("&", "?", ""));
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package io.mailtrap.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonValue;
5+
6+
public enum SendingStream {
7+
ANY("any"),
8+
TRANSACTIONAL("transactional"),
9+
BULK("bulk");
10+
11+
private final String value;
12+
13+
SendingStream(String value) {
14+
this.value = value;
15+
}
16+
17+
@JsonValue
18+
public String getValue() {
19+
return value;
20+
}
21+
22+
@Override
23+
public String toString() {
24+
return value;
25+
}
26+
27+
@JsonCreator
28+
public static SendingStream fromValue(String value) {
29+
for (SendingStream type : SendingStream.values()) {
30+
if (type.value.equalsIgnoreCase(value)) {
31+
return type;
32+
}
33+
}
34+
throw new IllegalArgumentException("Unknown value: " + value);
35+
}
36+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.mailtrap.model.response.stats;
2+
3+
import com.fasterxml.jackson.annotation.JsonAnySetter;
4+
import lombok.Data;
5+
6+
@Data
7+
public class SendingStatGroupResponse {
8+
9+
private String name;
10+
private Object value;
11+
private SendingStatsResponse stats;
12+
13+
@JsonAnySetter
14+
public void setDynamicField(String key, Object value) {
15+
if (!"stats".equals(key)) {
16+
this.name = key;
17+
this.value = value;
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)