MT-22401: Add Email Campaigns API - #250
Conversation
📝 WalkthroughWalkthroughThe PR adds email campaign models, request contracts, validation, token-scoped REST resources, lifecycle operations, statistics retrieval, integration and unit tests, and a runnable console example. ChangesEmail campaigns API
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Example
participant AccountResource
participant CampaignResource
participant MailtrapAPI
Example->>AccountResource: resolve campaign collection or campaign resource
AccountResource-->>Example: return token-scoped resource
Example->>CampaignResource: list, create, update, or invoke lifecycle action
CampaignResource->>MailtrapAPI: send REST request
MailtrapAPI-->>CampaignResource: return campaign or statistics response
CampaignResource-->>Example: map and return result
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: 2
🧹 Nitpick comments (1)
tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignCollectionResourceTests.cs (1)
19-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover collection operations, not only construction.
Add tests for
GetAllwithtoken,per_page, andsearch, plusCreaterequest/response mapping. These are the main behaviors introduced byEmailCampaignCollectionResourceand are currently untested.🤖 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 `@tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignCollectionResourceTests.cs` around lines 19 - 58, The EmailCampaignCollectionResource tests currently cover only construction and URI behavior; add coverage for its collection operations. Extend the test fixture around CreateResource to verify GetAll passes token, per_page, and search parameters correctly, and verify Create maps the request to the command and maps the response back to the expected resource model.
🤖 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/Mailtrap.Example.EmailCampaigns/EmailCampaigns.cs`:
- Around line 100-115: Change the EmailCampaigns example so
campaignResource.Start is not executed by default; place it behind an explicit
opt-in snippet or command. When opted in and a campaign is started, call
campaignResource.Terminate before cleanup, while preserving stats behavior as
appropriate. Verify the equivalent Mailtrap app example still accurately
reflects this public lifecycle and update it if needed.
- Around line 107-111: Update the GetStats call in the campaign example to use a
statistics window derived from the current execution time, covering the campaign
actions created during that run, instead of fixed May 2026 dates. Keep the
existing stats logging unchanged.
---
Nitpick comments:
In
`@tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignCollectionResourceTests.cs`:
- Around line 19-58: The EmailCampaignCollectionResource tests currently cover
only construction and URI behavior; add coverage for its collection operations.
Extend the test fixture around CreateResource to verify GetAll passes token,
per_page, and search parameters correctly, and verify Create maps the request to
the command and maps the response back to the expected resource model.
🪄 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: e005b093-9047-44b0-9f09-14a1c4114666
📒 Files selected for processing (61)
Mailtrap.slnREADME.mdexamples/Mailtrap.Example.EmailCampaigns/EmailCampaigns.csexamples/Mailtrap.Example.EmailCampaigns/Mailtrap.Example.EmailCampaigns.csprojexamples/Mailtrap.Example.EmailCampaigns/Properties/launchSettings.jsonexamples/Mailtrap.Example.EmailCampaigns/appsettings.jsonsrc/Mailtrap.Abstractions/Accounts/IAccountResource.cssrc/Mailtrap.Abstractions/EmailCampaigns/IEmailCampaignCollectionResource.cssrc/Mailtrap.Abstractions/EmailCampaigns/IEmailCampaignResource.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/CampaignState.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/DeliveryMode.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaign.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignDeliveryOptions.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignList.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignListFilter.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStateError.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStateMetadata.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStats.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStatsFilter.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignTemplate.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignType.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignsPagination.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/ReplyTo.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/CreateEmailCampaignRequest.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/EmailCampaignTemplateAttributes.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/ScheduleEmailCampaignRequest.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/UpdateEmailCampaignRequest.cssrc/Mailtrap.Abstractions/EmailCampaigns/Validators/CreateEmailCampaignRequestValidator.cssrc/Mailtrap.Abstractions/EmailCampaigns/Validators/ScheduleEmailCampaignRequestValidator.cssrc/Mailtrap.Abstractions/EmailCampaigns/Validators/UpdateEmailCampaignRequestValidator.cssrc/Mailtrap.Abstractions/GlobalSuppressions.cssrc/Mailtrap.Abstractions/GlobalUsings.cssrc/Mailtrap/Accounts/AccountResource.cssrc/Mailtrap/Core/Constants/UrlSegments.cssrc/Mailtrap/EmailCampaigns/EmailCampaignCollectionResource.cssrc/Mailtrap/EmailCampaigns/EmailCampaignResource.cssrc/Mailtrap/EmailCampaigns/Responses/EmailCampaignListResponseDto.cssrc/Mailtrap/EmailCampaigns/Responses/EmailCampaignResponseDto.cssrc/Mailtrap/EmailCampaigns/Responses/EmailCampaignStatsResponseDto.cssrc/Mailtrap/GlobalUsings.cstests/Mailtrap.IntegrationTests/EmailCampaigns/Create_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Create_Unprocessable.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/EmailCampaignIntegrationTests.cstests/Mailtrap.IntegrationTests/EmailCampaigns/GetAll_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/GetDetails_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/GetStats_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Schedule_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Start_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Start_Unprocessable.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Terminate_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Update_Success.jsontests/Mailtrap.IntegrationTests/GlobalUsings.cstests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cstests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignCollectionResourceTests.cstests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignRequestValidatorTests.cstests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignResourceTests.cstests/Mailtrap.UnitTests/EmailCampaigns/Requests/CreateEmailCampaignRequestTests.cstests/Mailtrap.UnitTests/EmailCampaigns/Requests/ScheduleEmailCampaignRequestTests.cstests/Mailtrap.UnitTests/EmailCampaigns/Requests/UpdateEmailCampaignRequestTests.cstests/Mailtrap.UnitTests/GlobalUsings.cstests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs
|
Addressed CodeRabbit review feedback in 8fc13fc:
Verified: |
8fc13fc to
711af62
Compare
Decisions: - Request bodies are flat per the current OpenAPI contract: the Create/Update request DTO envelopes and their ToDto() extensions are deleted; the public requests are posted directly. - Single-object and stats responses unwrap the data envelope via internal EmailCampaignResponseDto/EmailCampaignStatsResponseDto (Webhooks precedent). - Delete returns Task via RestResource.DeleteWithStatusCodeResult() to match the API's 204 No Content. - Five lifecycle endpoints (start/schedule/cancel/terminate/reset) POST to sub-segments via RestResourceCommandFactory.CreatePost; ScheduleEmailCampaignRequest carries a DateTimeOffset validated as future and at most 1 month ahead. - DomainId is a positive int64 sending domain ID (as returned by the Sending Domains endpoints) validated with NotNull + GreaterThan(0); a TemplateAttributes.Subject required-on-create rule replaces the dropped Scheduled/ScheduledFor rules.
Decisions: - Gate Start() behind MAILTRAP_START_CAMPAIGN=true so the example does not send real emails by default; Terminate() the campaign before cleanup when opted in - Derive the GetStats window from the current run time (last 7 days) instead of hardcoded May 2026 dates - Keep the date formatter in a partial Program member to stay under the CA1506 coupling limit for the top-level statements
711af62 to
027e001
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)
tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignRequestValidatorTests.cs (1)
158-164: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest the one-month boundary.
This test only rejects a date two months ahead. A validator that accepts dates more than one month ahead, but less than two months ahead, will still pass.
Add a case such as
DateTimeOffset.UtcNow.AddMonths(1).AddDays(1). Assert that it fails validation.🤖 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 `@tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignRequestValidatorTests.cs` around lines 158 - 164, Update Schedule_WithDatetimeMoreThanOneMonthAhead_ShouldFail to use a date just beyond the one-month limit, such as DateTimeOffset.UtcNow.AddMonths(1).AddDays(1), and retain the assertion that the Datetime field has a validation error. This must verify the one-month boundary rather than only rejecting dates two months ahead.
🤖 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
`@tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignRequestValidatorTests.cs`:
- Around line 158-164: Update
Schedule_WithDatetimeMoreThanOneMonthAhead_ShouldFail to use a date just beyond
the one-month limit, such as DateTimeOffset.UtcNow.AddMonths(1).AddDays(1), and
retain the assertion that the Datetime field has a validation error. This must
verify the one-month boundary rather than only rejecting dates two months ahead.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f175993c-5cca-4fc9-8a56-ef627601e810
📒 Files selected for processing (60)
Mailtrap.slnREADME.mdexamples/Mailtrap.Example.EmailCampaigns/EmailCampaigns.csexamples/Mailtrap.Example.EmailCampaigns/Mailtrap.Example.EmailCampaigns.csprojexamples/Mailtrap.Example.EmailCampaigns/Properties/launchSettings.jsonexamples/Mailtrap.Example.EmailCampaigns/appsettings.jsonsrc/Mailtrap.Abstractions/Accounts/IAccountResource.cssrc/Mailtrap.Abstractions/EmailCampaigns/IEmailCampaignCollectionResource.cssrc/Mailtrap.Abstractions/EmailCampaigns/IEmailCampaignResource.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/CampaignState.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/DeliveryMode.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaign.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignDeliveryOptions.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignList.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignListFilter.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStateError.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStateMetadata.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStats.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStatsFilter.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignTemplate.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignsPagination.cssrc/Mailtrap.Abstractions/EmailCampaigns/Models/ReplyTo.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/CreateEmailCampaignRequest.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/EmailCampaignTemplateAttributes.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/ScheduleEmailCampaignRequest.cssrc/Mailtrap.Abstractions/EmailCampaigns/Requests/UpdateEmailCampaignRequest.cssrc/Mailtrap.Abstractions/EmailCampaigns/Validators/CreateEmailCampaignRequestValidator.cssrc/Mailtrap.Abstractions/EmailCampaigns/Validators/ScheduleEmailCampaignRequestValidator.cssrc/Mailtrap.Abstractions/EmailCampaigns/Validators/UpdateEmailCampaignRequestValidator.cssrc/Mailtrap.Abstractions/GlobalSuppressions.cssrc/Mailtrap.Abstractions/GlobalUsings.cssrc/Mailtrap/Accounts/AccountResource.cssrc/Mailtrap/Core/Constants/UrlSegments.cssrc/Mailtrap/EmailCampaigns/EmailCampaignCollectionResource.cssrc/Mailtrap/EmailCampaigns/EmailCampaignResource.cssrc/Mailtrap/EmailCampaigns/Responses/EmailCampaignListResponseDto.cssrc/Mailtrap/EmailCampaigns/Responses/EmailCampaignResponseDto.cssrc/Mailtrap/EmailCampaigns/Responses/EmailCampaignStatsResponseDto.cssrc/Mailtrap/GlobalUsings.cstests/Mailtrap.IntegrationTests/EmailCampaigns/Create_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Create_Unprocessable.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/EmailCampaignIntegrationTests.cstests/Mailtrap.IntegrationTests/EmailCampaigns/GetAll_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/GetDetails_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/GetStats_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Schedule_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Start_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Start_Unprocessable.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Terminate_Success.jsontests/Mailtrap.IntegrationTests/EmailCampaigns/Update_Success.jsontests/Mailtrap.IntegrationTests/GlobalUsings.cstests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cstests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignCollectionResourceTests.cstests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignRequestValidatorTests.cstests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignResourceTests.cstests/Mailtrap.UnitTests/EmailCampaigns/Requests/CreateEmailCampaignRequestTests.cstests/Mailtrap.UnitTests/EmailCampaigns/Requests/ScheduleEmailCampaignRequestTests.cstests/Mailtrap.UnitTests/EmailCampaigns/Requests/UpdateEmailCampaignRequestTests.cstests/Mailtrap.UnitTests/GlobalUsings.cstests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs
🚧 Files skipped from review as they are similar to previous changes (53)
- examples/Mailtrap.Example.EmailCampaigns/Mailtrap.Example.EmailCampaigns.csproj
- src/Mailtrap/GlobalUsings.cs
- README.md
- tests/Mailtrap.IntegrationTests/EmailCampaigns/Terminate_Success.json
- src/Mailtrap.Abstractions/EmailCampaigns/Models/DeliveryMode.cs
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStatsFilter.cs
- tests/Mailtrap.UnitTests/GlobalUsings.cs
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignDeliveryOptions.cs
- src/Mailtrap/EmailCampaigns/Responses/EmailCampaignListResponseDto.cs
- src/Mailtrap/EmailCampaigns/Responses/EmailCampaignStatsResponseDto.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/Schedule_Success.json
- src/Mailtrap.Abstractions/EmailCampaigns/Validators/ScheduleEmailCampaignRequestValidator.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/Create_Success.json
- tests/Mailtrap.IntegrationTests/EmailCampaigns/GetStats_Success.json
- tests/Mailtrap.IntegrationTests/GlobalUsings.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/Start_Unprocessable.json
- examples/Mailtrap.Example.EmailCampaigns/appsettings.json
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStateError.cs
- src/Mailtrap.Abstractions/Accounts/IAccountResource.cs
- src/Mailtrap.Abstractions/EmailCampaigns/IEmailCampaignCollectionResource.cs
- examples/Mailtrap.Example.EmailCampaigns/Properties/launchSettings.json
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignList.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/Start_Success.json
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignsPagination.cs
- src/Mailtrap.Abstractions/EmailCampaigns/IEmailCampaignResource.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/GetAll_Success.json
- src/Mailtrap.Abstractions/EmailCampaigns/Requests/UpdateEmailCampaignRequest.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/GetDetails_Success.json
- tests/Mailtrap.UnitTests/EmailCampaigns/Requests/CreateEmailCampaignRequestTests.cs
- src/Mailtrap/EmailCampaigns/Responses/EmailCampaignResponseDto.cs
- tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/Create_Unprocessable.json
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignTemplate.cs
- tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignCollectionResourceTests.cs
- src/Mailtrap.Abstractions/EmailCampaigns/Models/ReplyTo.cs
- tests/Mailtrap.UnitTests/EmailCampaigns/EmailCampaignResourceTests.cs
- tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs
- examples/Mailtrap.Example.EmailCampaigns/EmailCampaigns.cs
- src/Mailtrap/Core/Constants/UrlSegments.cs
- tests/Mailtrap.UnitTests/EmailCampaigns/Requests/ScheduleEmailCampaignRequestTests.cs
- Mailtrap.sln
- src/Mailtrap.Abstractions/EmailCampaigns/Requests/EmailCampaignTemplateAttributes.cs
- src/Mailtrap.Abstractions/EmailCampaigns/Models/CampaignState.cs
- src/Mailtrap.Abstractions/GlobalUsings.cs
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStats.cs
- src/Mailtrap/Accounts/AccountResource.cs
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignListFilter.cs
- src/Mailtrap/EmailCampaigns/EmailCampaignCollectionResource.cs
- src/Mailtrap.Abstractions/GlobalSuppressions.cs
- src/Mailtrap.Abstractions/EmailCampaigns/Models/EmailCampaignStateMetadata.cs
- tests/Mailtrap.IntegrationTests/EmailCampaigns/Update_Success.json
- tests/Mailtrap.IntegrationTests/EmailCampaigns/EmailCampaignIntegrationTests.cs
- src/Mailtrap/EmailCampaigns/EmailCampaignResource.cs
Motivation
MT-22401
Port the Email Campaigns public API (MT-21113) to the .NET SDK.
Changes
client.Account(id).EmailCampaigns()/.EmailCampaign(id)covering the full contract: list (token/per_page/search filter), get, create, update, delete (204 →Task), the five lifecycle actions (Start,Schedule,Cancel,Terminate,Reset), andGetStatswith an optional date windowdata-envelope response DTOs (Webhooks precedent), int64DomainId/DomainNamematching the Sending Domains endpoints,Rapid/Gradualdelivery modes, 10-valueCampaignState, audience id lists, template attributes withBodyHtml/BodyText/MergeTags, per-recipient state-metadata errorsTemplateAttributes.SubjectandFromLocalPartrequired on create;Scheduledatetime must be in the future and ≤1 month aheadHow to test
Mailtrap.Example.EmailCampaignswith a real API token and a verified sending domain — create a draft, update design/audience, schedule + cancel, fetch stats, deleteCancelon a draft) surfaces the API error messageNote: the endpoint is token-scoped; the resource hangs off
Account(...)for API-shape consistency but the URI is/api/email_campaigns(asserted by tests).Summary by CodeRabbit