Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ You can find the [Mailtrap Java API reference](https://mailtrap.github.io/mailtr
- [Sending Domains](examples/java/io/mailtrap/examples/sendingdomains/SendingDomainsExample.java)
- [Company Info](examples/java/io/mailtrap/examples/companyinfo/CompanyInfoExample.java)
- [Suppressions](examples/java/io/mailtrap/examples/suppressions/SuppressionsExample.java)
- [Tracking Opt-outs](examples/java/io/mailtrap/examples/trackingoptouts/TrackingOptOutsExample.java)
- [Stats](examples/java/io/mailtrap/examples/sending/StatsExample.java)
- [Email Logs](examples/java/io/mailtrap/examples/emaillogs/EmailLogsExample.java)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.factory.MailtrapClientFactory;
import io.mailtrap.model.SendingStream;
import io.mailtrap.model.request.suppressions.CreateSuppressionRequest;
import io.mailtrap.model.request.suppressions.SuppressionListFilter;

public class SuppressionsExample {

private static final String TOKEN = System.getenv("MAILTRAP_API_KEY");
private static final long ACCOUNT_ID = Long.parseLong(System.getenv("MAILTRAP_ACCOUNT_ID"));
private static final long DOMAIN_ID = Long.parseLong(System.getenv("MAILTRAP_DOMAIN_ID"));
private static final String EMAIL = "example@mailtrap.io";

public static void main(String[] args) {
Expand All @@ -15,14 +19,36 @@ public static void main(String[] args) {
.build();

final var client = MailtrapClientFactory.createMailtrapClient(config);
final var suppressions = client.sendingApi().suppressions();

final var searchResponse = client.sendingApi().suppressions()
.search(ACCOUNT_ID, EMAIL);
// Add an email to the suppression list. Type defaults to "manual import" when omitted.
final var created = suppressions.createSuppression(
ACCOUNT_ID,
CreateSuppressionRequest.builder()
.email(EMAIL)
.domainId(DOMAIN_ID)
.sendingStream(SendingStream.TRANSACTIONAL)
.build()
);

System.out.println(created);

final var searchResponse = suppressions.search(ACCOUNT_ID, EMAIL);

System.out.println(searchResponse);

// Filter by email and creation time, and page with lastId
System.out.println(suppressions.search(
ACCOUNT_ID,
SuppressionListFilter.builder()
.email(EMAIL)
.startTime("2025-01-01T00:00:00Z")
.endTime("2025-12-31T23:59:59Z")
.build()
));

if (!searchResponse.isEmpty()) {
final var deletedSuppression = client.sendingApi().suppressions()
final var deletedSuppression = suppressions
.deleteSuppression(ACCOUNT_ID, searchResponse.get(0).getId());

System.out.println(deletedSuppression);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.mailtrap.examples.trackingoptouts;

import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.factory.MailtrapClientFactory;
import io.mailtrap.model.request.trackingoptouts.CreateTrackingOptOutRequest;
import io.mailtrap.model.request.trackingoptouts.TrackingOptOutListFilter;

public class TrackingOptOutsExample {

private static final String TOKEN = System.getenv("MAILTRAP_API_KEY");
private static final long DOMAIN_ID = Long.parseLong(System.getenv("MAILTRAP_DOMAIN_ID"));
private static final String EMAIL = "tracked@example.com";

public static void main(String[] args) {
final var config = new MailtrapConfig.Builder()
.token(TOKEN)
.build();

final var client = MailtrapClientFactory.createMailtrapClient(config);
final var trackingOptOuts = client.sendingApi().trackingOptOuts();

// Opt an email out of open and click tracking for a sending domain
final var created = trackingOptOuts.createTrackingOptOut(
CreateTrackingOptOutRequest.builder()
.email(EMAIL)
.domainId(DOMAIN_ID)
.build()
);

System.out.println(created);

// Get tracking opt-outs (up to 1000 per request)
var page = trackingOptOuts.getTrackingOptOuts(null);
System.out.println(page.getData());

// Filter by email and creation time
System.out.println(trackingOptOuts.getTrackingOptOuts(
TrackingOptOutListFilter.builder()
.email(EMAIL)
.startTime("2025-01-01T00:00:00Z")
.endTime("2025-12-31T23:59:59Z")
.build()
));

// Page through the full list, following the cursor
while (page.getLastId() != null) {
page = trackingOptOuts.getTrackingOptOuts(
TrackingOptOutListFilter.builder().lastId(page.getLastId()).build()
);
System.out.println(page.getData());
}

// Remove an email from the tracking opt-out list. Returns the deleted record.
System.out.println(trackingOptOuts.deleteTrackingOptOut(created.getId()));
}
}
21 changes: 21 additions & 0 deletions src/main/java/io/mailtrap/api/suppressions/Suppressions.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.mailtrap.api.suppressions;

import io.mailtrap.model.request.suppressions.CreateSuppressionRequest;
import io.mailtrap.model.request.suppressions.SuppressionListFilter;
import io.mailtrap.model.response.suppressions.SuppressionsResponse;

import java.util.List;
Expand All @@ -15,6 +17,25 @@ public interface Suppressions {
*/
List<SuppressionsResponse> search(long accountId, String email);

/**
* List and search suppressions. The endpoint returns up to 1000 suppressions per request;
* pass the last returned ID as {@code lastId} to fetch the next page.
*
* @param accountId - unique account ID
* @param filter - optional filtering and pagination parameters
* @return a list of suppressions
*/
List<SuppressionsResponse> search(long accountId, SuppressionListFilter filter);

/**
* Add an email address to the account's suppression list.
*
* @param accountId - unique account ID
* @param request - request data
* @return the created suppression
*/
SuppressionsResponse createSuppression(long accountId, CreateSuppressionRequest request);

/**
* Delete a suppression by ID. Mailtrap will no longer prevent sending to this email unless it's recorded in suppressions again.
*
Expand Down
25 changes: 24 additions & 1 deletion src/main/java/io/mailtrap/api/suppressions/SuppressionsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import io.mailtrap.api.apiresource.ApiResource;
import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.http.RequestData;
import io.mailtrap.model.request.suppressions.CreateSuppressionRequest;
import io.mailtrap.model.request.suppressions.SuppressionListFilter;
import io.mailtrap.model.response.suppressions.SuppressionResponse;
import io.mailtrap.model.response.suppressions.SuppressionsResponse;

import java.net.URLEncoder;
Expand All @@ -22,7 +25,17 @@ public SuppressionsImpl(final MailtrapConfig config) {

@Override
public List<SuppressionsResponse> search(final long accountId, final String email) {
final var queryParams = RequestData.buildQueryParams(entry("email", Optional.ofNullable(email)));
return search(accountId, SuppressionListFilter.builder().email(email).build());
}

@Override
public List<SuppressionsResponse> search(final long accountId, final SuppressionListFilter filter) {
final var queryParams = RequestData.buildQueryParams(
entry("email", Optional.ofNullable(filter).map(SuppressionListFilter::getEmail)),
entry("start_time", Optional.ofNullable(filter).map(SuppressionListFilter::getStartTime)),
entry("end_time", Optional.ofNullable(filter).map(SuppressionListFilter::getEndTime)),
entry("last_id", Optional.ofNullable(filter).map(SuppressionListFilter::getLastId))
);

return
httpClient.getList(
Expand All @@ -32,6 +45,16 @@ public List<SuppressionsResponse> search(final long accountId, final String emai
);
}

@Override
public SuppressionsResponse createSuppression(final long accountId, final CreateSuppressionRequest request) {
return httpClient.post(
String.format(apiHost + "/api/accounts/%d/suppressions", accountId),
request,
new RequestData(),
SuppressionResponse.class
).getData();
}

@Override
public SuppressionsResponse deleteSuppression(final long accountId, final String suppressionId) {
if (suppressionId == null || suppressionId.isBlank()) {
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/io/mailtrap/api/trackingoptouts/TrackingOptOuts.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.mailtrap.api.trackingoptouts;

import io.mailtrap.model.request.trackingoptouts.CreateTrackingOptOutRequest;
import io.mailtrap.model.request.trackingoptouts.TrackingOptOutListFilter;
import io.mailtrap.model.response.trackingoptouts.TrackingOptOut;
import io.mailtrap.model.response.trackingoptouts.TrackingOptOutListResponse;

public interface TrackingOptOuts {

/**
* List email addresses that have opted out of open and click tracking.
* The endpoint returns up to 1000 records per request; pass the previous response's
* {@code lastId} to fetch the next page.
*
* @param filter - optional filtering and pagination parameters
* @return the page of tracking opt-outs and the cursor for the next page
*/
TrackingOptOutListResponse getTrackingOptOuts(TrackingOptOutListFilter filter);

/**
* Add an email address to the tracking opt-out list for a sending domain.
*
* @param request - request data
* @return the created tracking opt-out
*/
TrackingOptOut createTrackingOptOut(CreateTrackingOptOutRequest request);

/**
* Remove an email address from the tracking opt-out list so open and click tracking can
* apply again.
*
* @param trackingOptOutId - unique tracking opt-out ID
* @return the attributes of the deleted tracking opt-out
*/
TrackingOptOut deleteTrackingOptOut(String trackingOptOutId);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.mailtrap.api.trackingoptouts;

import io.mailtrap.Constants;
import io.mailtrap.api.apiresource.ApiResource;
import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.http.RequestData;
import io.mailtrap.model.request.trackingoptouts.CreateTrackingOptOutRequest;
import io.mailtrap.model.request.trackingoptouts.TrackingOptOutListFilter;
import io.mailtrap.model.response.trackingoptouts.TrackingOptOut;
import io.mailtrap.model.response.trackingoptouts.TrackingOptOutListResponse;
import io.mailtrap.model.response.trackingoptouts.TrackingOptOutResponse;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

import static io.mailtrap.http.RequestData.entry;

public class TrackingOptOutsImpl extends ApiResource implements TrackingOptOuts {

private static final String BASE_PATH = "/api/tracking_opt_outs";

public TrackingOptOutsImpl(final MailtrapConfig config) {
super(config);
this.apiHost = Constants.GENERAL_HOST;
}

@Override
public TrackingOptOutListResponse getTrackingOptOuts(final TrackingOptOutListFilter filter) {
final var queryParams = RequestData.buildQueryParams(
entry("email", Optional.ofNullable(filter).map(TrackingOptOutListFilter::getEmail)),
entry("start_time", Optional.ofNullable(filter).map(TrackingOptOutListFilter::getStartTime)),
entry("end_time", Optional.ofNullable(filter).map(TrackingOptOutListFilter::getEndTime)),
entry("last_id", Optional.ofNullable(filter).map(TrackingOptOutListFilter::getLastId))
);

return httpClient.get(
apiHost + BASE_PATH,
new RequestData(queryParams),
TrackingOptOutListResponse.class
);
}

@Override
public TrackingOptOut createTrackingOptOut(final CreateTrackingOptOutRequest request) {
return httpClient.post(
apiHost + BASE_PATH,
request,
new RequestData(),
TrackingOptOutResponse.class
).getData();
}

@Override
public TrackingOptOut deleteTrackingOptOut(final String trackingOptOutId) {
if (trackingOptOutId == null || trackingOptOutId.isBlank()) {
throw new IllegalArgumentException("trackingOptOutId must not be null or blank");
}

return httpClient.delete(
String.format(
apiHost + BASE_PATH + "/%s",
URLEncoder.encode(trackingOptOutId, StandardCharsets.UTF_8)
),
new RequestData(),
TrackingOptOut.class
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.mailtrap.api.sendingemails.SendingEmails;
import io.mailtrap.api.stats.Stats;
import io.mailtrap.api.suppressions.Suppressions;
import io.mailtrap.api.trackingoptouts.TrackingOptOuts;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;
Expand All @@ -21,6 +22,7 @@ public class MailtrapEmailSendingApi {
private final SendingDomains domains;
private final CompanyInfo companyInfo;
private final Suppressions suppressions;
private final TrackingOptOuts trackingOptOuts;
private final Stats stats;
private final EmailLogs emailLogs;
}
5 changes: 4 additions & 1 deletion src/main/java/io/mailtrap/factory/MailtrapClientFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.mailtrap.api.stats.StatsImpl;
import io.mailtrap.api.subaccounts.SubAccountsImpl;
import io.mailtrap.api.suppressions.SuppressionsImpl;
import io.mailtrap.api.trackingoptouts.TrackingOptOutsImpl;
import io.mailtrap.api.testingemails.TestingEmailsImpl;
import io.mailtrap.api.webhooks.WebhooksImpl;
import io.mailtrap.client.MailtrapClient;
Expand Down Expand Up @@ -137,10 +138,12 @@ private static MailtrapEmailSendingApi createSendingApi(final MailtrapConfig con
final var domains = new SendingDomainsImpl(config);
final var companyInfo = new CompanyInfoImpl(config);
final var suppressions = new SuppressionsImpl(config);
final var trackingOptOuts = new TrackingOptOutsImpl(config);
final var stats = new StatsImpl(config);
final var emailLogs = new EmailLogsImpl(config);

return new MailtrapEmailSendingApi(emails, domains, companyInfo, suppressions, stats, emailLogs);
return new MailtrapEmailSendingApi(emails, domains, companyInfo, suppressions, trackingOptOuts, stats,
emailLogs);
}

private static MailtrapEmailTestingApi createTestingApi(final MailtrapConfig config) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.mailtrap.model.request.suppressions;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.mailtrap.model.AbstractModel;
import io.mailtrap.model.SendingStream;
import io.mailtrap.model.response.suppressions.SuppressionType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CreateSuppressionRequest extends AbstractModel {

private String email;

@JsonProperty("domain_id")
private Long domainId;

@JsonProperty("sending_stream")
private SendingStream sendingStream;

/**
* Reason for the suppression. The API defaults to {@code manual import} when omitted.
*/
private SuppressionType type;

}
Loading
Loading