Skip to content
Open
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ You can find the [Mailtrap Java API reference](https://mailtrap.github.io/mailtr

- [Email Templates](examples/java/io/mailtrap/examples/emailtemplates/EmailTemplatesExample.java)

### Email Marketing API

- [Email Campaigns](examples/java/io/mailtrap/examples/emailcampaigns/EmailCampaignsExample.java)

## Contributing

Bug reports and pull requests are welcome on [GitHub](https://github.com/mailtrap/mailtrap-java). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](CODE_OF_CONDUCT.md).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package io.mailtrap.examples.emailcampaigns;

import io.mailtrap.api.emailcampaigns.EmailCampaignListFilter;
import io.mailtrap.api.emailcampaigns.EmailCampaignStatsFilter;
import io.mailtrap.config.MailtrapConfig;
import io.mailtrap.factory.MailtrapClientFactory;
import io.mailtrap.model.DeliveryMode;
import io.mailtrap.model.request.emailcampaigns.CreateEmailCampaign;
import io.mailtrap.model.request.emailcampaigns.ScheduleEmailCampaignRequest;
import io.mailtrap.model.request.emailcampaigns.TemplateAttributes;
import io.mailtrap.model.request.emailcampaigns.UpdateEmailCampaign;
import io.mailtrap.model.response.emailcampaigns.DeliveryOptions;
import io.mailtrap.model.response.emailcampaigns.ReplyTo;

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;

public class EmailCampaignsExample {

private static final String TOKEN = "<YOUR MAILTRAP TOKEN>";
// ID of a verified sending domain on the account, as returned by the Sending Domains endpoints.
private static final long DOMAIN_ID = 4321L;
private static final long CONTACT_LIST_ID = 55L;

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

final var client = MailtrapClientFactory.createMailtrapClient(config);

// The campaign endpoints are token-scoped: the account is resolved from the API token.
final var campaigns = client.emailCampaignsApi().emailCampaigns();

// List campaigns (newest first). Pass null for the first page with API defaults.
final var page = campaigns.getEmailCampaigns(
EmailCampaignListFilter.builder()
.perPage(50)
.search("Spring")
.token(1)
.build());
System.out.println(page);

// Create a campaign — it starts in the `draft` state. The request body is flat.
final var created = campaigns.createEmailCampaign(
CreateEmailCampaign.builder()
.name("Spring Sale")
.domainId(DOMAIN_ID)
.fromDisplayName("Acme Marketing")
.fromLocalPart("news")
.replyTo(ReplyTo.builder()
.displayName("Acme Support")
.localPart("support")
.domain("acme.com")
.build())
.templateAttributes(TemplateAttributes.builder()
.subject("Spring is here — 30% off")
.build())
.contactListIds(List.of(CONTACT_LIST_ID))
.build());
System.out.println(created.getData());

final var campaignId = created.getData().getId();

// Retrieve a single campaign.
final var fetched = campaigns.getEmailCampaign(campaignId);
System.out.println(fetched.getData());

// Update is a PATCH — only the provided fields change. The template is edited in place;
// `bodyHtml` is the design and must contain an unsubscribe link.
final var updated = campaigns.updateEmailCampaign(campaignId,
UpdateEmailCampaign.builder()
.name("Spring Sale (updated)")
.templateAttributes(TemplateAttributes.builder()
.subject("New subject")
.bodyHtml("<html><body><h1>Hi {{first_name}}!</h1>"
+ "<p><a href=\"__unsubscribe_url__\">Unsubscribe</a></p></body></html>")
.mergeTags(List.of("first_name"))
.build())
.deliveryMode(DeliveryMode.GRADUAL)
.deliveryOptions(DeliveryOptions.builder().emailsPerHour(1000).build())
.build());
System.out.println(updated.getData());

// Schedule the draft to send later — the time must be in the future, at most 1 month
// ahead; it comes back in currentStateMetadata.scheduledAt.
final var scheduled = campaigns.scheduleEmailCampaign(campaignId,
new ScheduleEmailCampaignRequest(OffsetDateTime.now(ZoneOffset.UTC).plusDays(1)));
System.out.println(scheduled.getData().getCurrentStateMetadata().getScheduledAt());

// Cancel the scheduled send — the campaign returns to `draft`.
final var cancelled = campaigns.cancelEmailCampaign(campaignId);
System.out.println(cancelled.getData().getCurrentState());

// Or start sending immediately.
final var started = campaigns.startEmailCampaign(campaignId);
System.out.println(started.getData().getCurrentState());

// Aggregated performance statistics; narrow the window with start/end dates (YYYY-MM-DD).
final var today = LocalDate.now(ZoneOffset.UTC);
final var stats = campaigns.getEmailCampaignStats(campaignId,
EmailCampaignStatsFilter.builder()
.startDate(today.minusDays(30).toString())
.endDate(today.toString())
.build());
System.out.println(stats.getData());

// Delete returns 204 No Content.
campaigns.deleteEmailCampaign(campaignId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.mailtrap.api.emailcampaigns;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* Filtering and pagination parameters for listing email campaigns. All fields are optional;
* {@code null} fields are omitted from the query string.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class EmailCampaignListFilter {

/**
* Number of campaigns per page (max 100, default 50).
*/
private Integer perPage;

/**
* Filter campaigns by name.
*/
private String search;

/**
* Page number to retrieve (page-token pagination, default 1).
*/
private Integer token;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.mailtrap.api.emailcampaigns;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* Aggregation window for email campaign statistics. Both fields are optional; {@code null}
* fields are omitted from the query string and the window defaults to the whole period since
* the campaign was last started.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class EmailCampaignStatsFilter {

/**
* Start of the aggregation window (inclusive), in {@code YYYY-MM-DD} format.
*/
private String startDate;

/**
* End of the aggregation window (inclusive), in {@code YYYY-MM-DD} format.
*/
private String endDate;
}
116 changes: 116 additions & 0 deletions src/main/java/io/mailtrap/api/emailcampaigns/EmailCampaigns.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package io.mailtrap.api.emailcampaigns;

import io.mailtrap.model.request.emailcampaigns.CreateEmailCampaign;
import io.mailtrap.model.request.emailcampaigns.ScheduleEmailCampaignRequest;
import io.mailtrap.model.request.emailcampaigns.UpdateEmailCampaign;
import io.mailtrap.model.response.emailcampaigns.EmailCampaignListResponse;
import io.mailtrap.model.response.emailcampaigns.EmailCampaignResponse;
import io.mailtrap.model.response.emailcampaigns.EmailCampaignStatsResponse;

/**
* Email Campaigns API. Manage email marketing campaigns and retrieve their performance
* statistics.
*
* <p>The account is resolved from the API token, so these endpoints are token-scoped and the
* path is not account-scoped.
*/
public interface EmailCampaigns {

/**
* List the account's email campaigns, newest first.
*
* @param filter filtering and pagination parameters; {@code null} for the first page with
* API defaults
* @return a page of campaigns and the pagination metadata
*/
EmailCampaignListResponse getEmailCampaigns(EmailCampaignListFilter filter);

/**
* Create a new email campaign in the {@code draft} state.
*
* @param request the campaign attributes ({@code name}, {@code domainId},
* {@code fromLocalPart} and a template {@code subject} are required)
* @return the created email campaign
*/
EmailCampaignResponse createEmailCampaign(CreateEmailCampaign request);

/**
* Get a single email campaign by ID.
*
* @param emailCampaignId unique email campaign ID
* @return the email campaign
*/
EmailCampaignResponse getEmailCampaign(long emailCampaignId);

/**
* Update an existing {@code draft} email campaign. Only the provided attributes are
* changed.
*
* @param emailCampaignId unique email campaign ID
* @param request the attributes to update
* @return the updated email campaign
*/
EmailCampaignResponse updateEmailCampaign(long emailCampaignId, UpdateEmailCampaign request);

/**
* Delete an email campaign. The campaign must not be in a sending state.
*
* @param emailCampaignId unique email campaign ID
*/
void deleteEmailCampaign(long emailCampaignId);

/**
* Start sending a {@code draft} campaign immediately.
*
* @param emailCampaignId unique email campaign ID
* @return the started email campaign
*/
EmailCampaignResponse startEmailCampaign(long emailCampaignId);

/**
* Schedule a {@code draft} campaign to start sending at a future time. The scheduled time
* is reported back in {@code currentStateMetadata.scheduledAt}.
*
* @param emailCampaignId unique email campaign ID
* @param request when to start sending the campaign
* @return the scheduled email campaign
*/
EmailCampaignResponse scheduleEmailCampaign(long emailCampaignId, ScheduleEmailCampaignRequest request);

/**
* Cancel a {@code scheduled} campaign, returning it to the {@code draft} state.
*
* @param emailCampaignId unique email campaign ID
* @return the cancelled email campaign
*/
EmailCampaignResponse cancelEmailCampaign(long emailCampaignId);

/**
* Terminate a campaign that is currently sending ({@code started}, {@code queued} or
* {@code paused}), aborting the in-flight send.
*
* @param emailCampaignId unique email campaign ID
* @return the terminated email campaign
*/
EmailCampaignResponse terminateEmailCampaign(long emailCampaignId);

/**
* Reset a {@code scheduled} campaign back to the {@code draft} state.
*
* @param emailCampaignId unique email campaign ID
* @return the reset email campaign
*/
EmailCampaignResponse resetEmailCampaign(long emailCampaignId);

/**
* Get aggregated performance statistics for an email campaign. If the campaign has never
* been started, all counts and rates are returned as {@code 0}.
*
* @param emailCampaignId unique email campaign ID
* @param filter aggregation window; {@code null} for the whole period since the
* campaign was last started
* @return aggregated campaign statistics
*/
EmailCampaignStatsResponse getEmailCampaignStats(long emailCampaignId, EmailCampaignStatsFilter filter);

}
Loading
Loading