MT-22401: Add Email Campaigns API - #65
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds a token-scoped Email Campaigns API with request and response models, campaign lifecycle operations, client integration, tests, fixtures, and a Java usage example. ChangesEmail Campaigns API
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant MailtrapClient
participant MailtrapEmailCampaignsApi
participant EmailCampaignsImpl
participant EmailCampaignsAPI
MailtrapClient->>MailtrapEmailCampaignsApi: access campaign API
MailtrapEmailCampaignsApi->>EmailCampaignsImpl: invoke campaign operation
EmailCampaignsImpl->>EmailCampaignsAPI: send request
EmailCampaignsAPI-->>EmailCampaignsImpl: return campaign or statistics response
EmailCampaignsImpl-->>MailtrapEmailCampaignsApi: deserialize response
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.java (1)
97-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover
per_pageandtokenrequest serialization.The suite asserts pagination fields from the response but never calls
getEmailCampaignswithperPageortoken. Add a matchingDataMockand test invocation so query-key/type regressions are caught.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.java` around lines 97 - 132, Add a dedicated getEmailCampaigns test using a matching DataMock response and invoke api.getEmailCampaigns with non-null perPage and token values. Assert the existing response expectations while ensuring the request serialization covers both pagination query keys and their numeric types.src/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.java (1)
1-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
CreateEmailCampaignandUpdateEmailCampaignare structurally duplicated and both depend on the response package for shared types.Both classes declare an identical set of fields (
name,mailsendDomainId,fromDisplayName,fromLocalPart,replyTo,templateAttributes,deliveryMode,deliveryOptions,contactListIds,contactSegmentIds) with the same annotations, and both importReplyTo/DeliveryOptionsfromio.mailtrap.model.response.emailcampaignsfor request bodies. This is a DRY violation and a layering smell (request DTOs depending on theresponsepackage for types that are genuinely shared).
src/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.java#L1-L71: extract the common fields into a shared abstract base (e.g.AbstractEmailCampaignRequest) that bothCreateEmailCampaignandUpdateEmailCampaignextend, and moveReplyTo/DeliveryOptionsto a neutral shared package (e.g.io.mailtrap.model.emailcampaigns) instead ofresponse.emailcampaigns.src/main/java/io/mailtrap/model/request/emailcampaigns/UpdateEmailCampaign.java#L1-L70: extend the same shared base class once introduced, removing the duplicated field declarations.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.java` around lines 1 - 71, The email campaign request DTOs duplicate fields and depend on response-only shared types. Create an AbstractEmailCampaignRequest containing the common fields and annotations, make CreateEmailCampaign and UpdateEmailCampaign extend it, and remove their duplicated declarations; move ReplyTo and DeliveryOptions from io.mailtrap.model.response.emailcampaigns to a neutral shared package and update both request DTOs and other references. Apply the changes in src/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.java#L1-L71 and src/main/java/io/mailtrap/model/request/emailcampaigns/UpdateEmailCampaign.java#L1-L70.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@examples/java/io/mailtrap/examples/emailcampaigns/EmailCampaignsExample.java`:
- Around line 81-82: Update the timestamp passed to
EmailCampaignsExample.scheduleEmailCampaign so it is always future-dated when
the example runs, preferably by deriving it from the current time; preserve the
existing UTC OffsetDateTime request construction.
---
Nitpick comments:
In
`@src/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.java`:
- Around line 1-71: The email campaign request DTOs duplicate fields and depend
on response-only shared types. Create an AbstractEmailCampaignRequest containing
the common fields and annotations, make CreateEmailCampaign and
UpdateEmailCampaign extend it, and remove their duplicated declarations; move
ReplyTo and DeliveryOptions from io.mailtrap.model.response.emailcampaigns to a
neutral shared package and update both request DTOs and other references. Apply
the changes in
src/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.java#L1-L71
and
src/main/java/io/mailtrap/model/request/emailcampaigns/UpdateEmailCampaign.java#L1-L70.
In `@src/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.java`:
- Around line 97-132: Add a dedicated getEmailCampaigns test using a matching
DataMock response and invoke api.getEmailCampaigns with non-null perPage and
token values. Assert the existing response expectations while ensuring the
request serialization covers both pagination query keys and their numeric types.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 46d36535-60d9-43fe-a60c-30f229087592
📒 Files selected for processing (38)
README.mdexamples/java/io/mailtrap/examples/emailcampaigns/EmailCampaignsExample.javasrc/main/java/io/mailtrap/api/emailcampaigns/EmailCampaigns.javasrc/main/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImpl.javasrc/main/java/io/mailtrap/client/MailtrapClient.javasrc/main/java/io/mailtrap/client/api/MailtrapEmailCampaignsApi.javasrc/main/java/io/mailtrap/factory/MailtrapClientFactory.javasrc/main/java/io/mailtrap/model/CampaignState.javasrc/main/java/io/mailtrap/model/DeliveryMode.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/ScheduleEmailCampaignRequest.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/TemplateAttributes.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/UpdateEmailCampaign.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/CampaignRecipientError.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/CurrentStateMetadata.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/DeliveryOptions.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaign.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignListResponse.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignResponse.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignStats.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignStatsResponse.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/Pagination.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/ReplyTo.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/Template.javasrc/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.javasrc/test/resources/api/emailcampaigns/cancelEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/createEmailCampaignRequest.jsonsrc/test/resources/api/emailcampaigns/createEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/getEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/getEmailCampaignStatsResponse.jsonsrc/test/resources/api/emailcampaigns/listEmailCampaignsResponse.jsonsrc/test/resources/api/emailcampaigns/resetEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/scheduleEmailCampaignRequest.jsonsrc/test/resources/api/emailcampaigns/scheduleEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/startEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/terminateEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/updateEmailCampaignRequest.jsonsrc/test/resources/api/emailcampaigns/updateEmailCampaignResponse.json
|
Addressed the CodeRabbit finding in 4761f45:
Verified: full |
4761f45 to
1715673
Compare
Decisions: - Request bodies are flat per the current contract — the email_campaign wrapper classes were deleted; CreateEmailCampaign/UpdateEmailCampaign extend AbstractModel and are passed directly - Single-object and stats responses unwrap through data-envelope types (EmailCampaignResponse, EmailCampaignStatsResponse), following the GetContactResponse precedent - deleteEmailCampaign returns void via Void.class since the API responds 204 No Content - Five lifecycle endpoints (start/schedule/cancel/terminate/reset) share a no-body POST helper; ScheduleEmailCampaignRequest.datetime is OffsetDateTime with @jsonformat(shape = STRING) because the mapper otherwise emits numeric timestamps - CampaignState carries the full 10-value enum — its @JsonCreator throws on unknown values, so stale values hard-fail against production
Decisions: - Derive the example's schedule time and stats date window from the current time instead of hardcoded dates, so the public example stays valid when run
1715673 to
12d3842
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.java (1)
46-51: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd request coverage for pagination tokens.
These tests only inspect tokens in the response. They do not send a token in a list request. A missing or incorrect
tokenquery parameter can pass this suite.Add a
DataMockentry that matches a token query parameter. Add a test that callsgetEmailCampaignswith a token and verifies the response.Also applies to: 96-131
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.java` around lines 46 - 51, Add pagination-token request coverage in EmailCampaignsImplTest: add a DataMock entry matching the token query parameter, then add a test that invokes getEmailCampaigns with that token and verifies the returned response. Keep the existing response-token assertions and non-token request cases unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.java`:
- Around line 46-51: Add pagination-token request coverage in
EmailCampaignsImplTest: add a DataMock entry matching the token query parameter,
then add a test that invokes getEmailCampaigns with that token and verifies the
returned response. Keep the existing response-token assertions and non-token
request cases unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1d7d94db-2b26-4d59-94cb-8159e95fc939
📒 Files selected for processing (38)
README.mdexamples/java/io/mailtrap/examples/emailcampaigns/EmailCampaignsExample.javasrc/main/java/io/mailtrap/api/emailcampaigns/EmailCampaigns.javasrc/main/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImpl.javasrc/main/java/io/mailtrap/client/MailtrapClient.javasrc/main/java/io/mailtrap/client/api/MailtrapEmailCampaignsApi.javasrc/main/java/io/mailtrap/factory/MailtrapClientFactory.javasrc/main/java/io/mailtrap/model/CampaignState.javasrc/main/java/io/mailtrap/model/DeliveryMode.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/CreateEmailCampaign.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/ScheduleEmailCampaignRequest.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/TemplateAttributes.javasrc/main/java/io/mailtrap/model/request/emailcampaigns/UpdateEmailCampaign.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/CampaignRecipientError.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/CurrentStateMetadata.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/DeliveryOptions.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaign.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignListResponse.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignResponse.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignStats.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignStatsResponse.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/Pagination.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/ReplyTo.javasrc/main/java/io/mailtrap/model/response/emailcampaigns/Template.javasrc/test/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImplTest.javasrc/test/resources/api/emailcampaigns/cancelEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/createEmailCampaignRequest.jsonsrc/test/resources/api/emailcampaigns/createEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/getEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/getEmailCampaignStatsResponse.jsonsrc/test/resources/api/emailcampaigns/listEmailCampaignsResponse.jsonsrc/test/resources/api/emailcampaigns/resetEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/scheduleEmailCampaignRequest.jsonsrc/test/resources/api/emailcampaigns/scheduleEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/startEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/terminateEmailCampaignResponse.jsonsrc/test/resources/api/emailcampaigns/updateEmailCampaignRequest.jsonsrc/test/resources/api/emailcampaigns/updateEmailCampaignResponse.json
🚧 Files skipped from review as they are similar to previous changes (34)
- src/test/resources/api/emailcampaigns/getEmailCampaignStatsResponse.json
- src/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignStatsResponse.java
- src/test/resources/api/emailcampaigns/scheduleEmailCampaignRequest.json
- src/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignListResponse.java
- src/test/resources/api/emailcampaigns/updateEmailCampaignRequest.json
- src/test/resources/api/emailcampaigns/scheduleEmailCampaignResponse.json
- src/test/resources/api/emailcampaigns/startEmailCampaignResponse.json
- src/test/resources/api/emailcampaigns/createEmailCampaignResponse.json
- src/test/resources/api/emailcampaigns/cancelEmailCampaignResponse.json
- src/test/resources/api/emailcampaigns/getEmailCampaignResponse.json
- src/main/java/io/mailtrap/client/api/MailtrapEmailCampaignsApi.java
- src/main/java/io/mailtrap/model/response/emailcampaigns/Template.java
- src/main/java/io/mailtrap/factory/MailtrapClientFactory.java
- src/test/resources/api/emailcampaigns/updateEmailCampaignResponse.json
- src/main/java/io/mailtrap/model/response/emailcampaigns/CampaignRecipientError.java
- src/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignStats.java
- src/main/java/io/mailtrap/model/request/emailcampaigns/ScheduleEmailCampaignRequest.java
- src/main/java/io/mailtrap/model/request/emailcampaigns/TemplateAttributes.java
- src/test/resources/api/emailcampaigns/terminateEmailCampaignResponse.json
- src/test/resources/api/emailcampaigns/resetEmailCampaignResponse.json
- src/main/java/io/mailtrap/model/response/emailcampaigns/ReplyTo.java
- src/main/java/io/mailtrap/model/request/emailcampaigns/UpdateEmailCampaign.java
- src/test/resources/api/emailcampaigns/listEmailCampaignsResponse.json
- src/main/java/io/mailtrap/model/response/emailcampaigns/EmailCampaignResponse.java
- README.md
- src/main/java/io/mailtrap/api/emailcampaigns/EmailCampaignsImpl.java
- src/main/java/io/mailtrap/model/response/emailcampaigns/CurrentStateMetadata.java
- src/main/java/io/mailtrap/model/CampaignState.java
- src/main/java/io/mailtrap/api/emailcampaigns/EmailCampaigns.java
- src/main/java/io/mailtrap/client/MailtrapClient.java
- src/main/java/io/mailtrap/model/DeliveryMode.java
- examples/java/io/mailtrap/examples/emailcampaigns/EmailCampaignsExample.java
- src/main/java/io/mailtrap/model/response/emailcampaigns/DeliveryOptions.java
- src/main/java/io/mailtrap/model/response/emailcampaigns/Pagination.java
mklocek
left a comment
There was a problem hiding this comment.
Looks ok but I'd consider using filters object wrapper for consistency and extendability
Decisions: - Replace positional list args and the stats overload pair with filter objects so new query params extend the filter, not the method signature - Mirror StatsFilter (Lombok @DaTa @builder) to match the sending-stats convention - Move Pagination out of the emailcampaigns package; the payload is generic and the next paginated resource should reuse it
Decisions:
- "/api/accounts/{account_id}/email_campaigns" does not exist, so there is no
need to contrast the real path against it
- Keep the positive fact that the account comes from the API token; it explains
why the path takes no account id
Decisions: - The backend allows deleting only a campaign in the draft state (EmailCampaign#validate_soft_delete), not merely a non-sending one - Examples deleted a campaign after start/terminate, which would 422; a started campaign can never return to draft, so they now delete a fresh draft
Motivation
MT-22401
Port the Email Campaigns public API (MT-21113) to the Java SDK.
Changes
client.emailCampaignsApi().emailCampaigns()covering the full contract: list (per_page/search/token), get, create, update, delete (204 →void), the five lifecycle actions (start,schedule,cancel,terminate,reset), and stats with an optional date windowdata-envelope response types, integerdomainId(matching the Sending Domains endpoints),RAPID/GRADUALdelivery modes, 10-valueCampaignState, audience id lists,TemplateAttributeswithbodyHtml/bodyText/mergeTags, per-recipient state-metadata errorsScheduleEmailCampaignRequestserializesdatetimeas ISO 8601 (@JsonFormat(shape = STRING)) — the default mapper would emit numeric timestampsHow to test
EmailCampaignsExamplewith a real API token and a verified sending domain — create a draft, update design/audience, schedule + cancel, fetch stats, deleteCampaignStateis fail-closed on unknown values)Summary by CodeRabbit
New Features
Documentation