Skip to content

MT-22401: Add Email Campaigns API - #72

Merged
Rabsztok merged 5 commits into
mainfrom
MT-22401-php-email-campaigns
Aug 14, 2026
Merged

MT-22401: Add Email Campaigns API#72
Rabsztok merged 5 commits into
mainfrom
MT-22401-php-email-campaigns

Conversation

@Rabsztok

@Rabsztok Rabsztok commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Draft until the server-side Email Campaigns API changes are released.

Motivation

MT-22401

Port the Email Campaigns public API (MT-21113) to the PHP SDK.

Changes

  • Add emailCampaigns() to the General client with the full contract: list (per_page/search/token), get, create, update, delete (204), the five lifecycle actions (start, schedule, cancel, terminate, reset), and stats with an optional date range
  • Typed request DTOs per the published OpenAPI schema: flat request bodies, integer domainId (a Sending Domains endpoint id), new TemplateAttributes (subject/bodyHtml/bodyText/mergeTags) and ReplyTo DTOs, audience id arrays (empty array clears the audience), rapid/gradual delivery modes, 10-value state constants
  • Full-lifecycle example in examples/email-campaigns/all.php + README/CHANGELOG entries

How to test

  • Run examples/email-campaigns/all.php with a real API token and a verified sending domain — create a draft, update design/audience, schedule + cancel, fetch stats, delete
  • Verify single-campaign responses expose the data payload and a lifecycle 422 surfaces the API error message

Summary by CodeRabbit

  • New Features
    • Added support for creating, viewing, updating, and deleting email campaigns.
    • Added campaign lifecycle controls, including scheduling, starting, cancelling, resetting, and terminating campaigns.
    • Added campaign listing with pagination and search filters.
    • Added performance statistics with optional date ranges.
    • Added options for templates, delivery modes, sender details, reply-to addresses, contact lists, and segments.
  • Documentation
    • Added email campaign documentation and a complete lifecycle example.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3dc17fb1-df3f-41aa-a5b3-9b61c4990e73

📥 Commits

Reviewing files that changed from the base of the PR and between bbc5cf8 and 82b5ec1.

📒 Files selected for processing (1)
  • src/Api/General/EmailCampaign.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Api/General/EmailCampaign.php

📝 Walkthrough

Walkthrough

Adds an account-scoped Email Campaign API client with request DTOs, CRUD, lifecycle operations, scheduling, statistics, client registration, tests, a PHP example, and README links.

Changes

Email Campaigns

Layer / File(s) Summary
Campaign request contracts
src/DTO/Request/EmailCampaign/*
Adds campaign states, delivery modes, nested request DTOs, payload serialization, and empty-update validation.
Campaign API and client wiring
src/Api/General/EmailCampaign.php, src/MailtrapGeneralClient.php, tests/MailtrapGeneralClientTest.php
Adds account-scoped listing, CRUD, lifecycle, scheduling, statistics, and client mapping.
Campaign operation coverage
tests/Api/General/EmailCampaignTest.php
Tests request wiring, serialization, validation, lifecycle operations, date conversion, statistics filters, and response handling.
Usage examples and documentation
examples/email-campaigns/all.php, examples/README.md, README.md
Adds a complete campaign workflow example and links it from the documentation indexes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to 82b5e

The PR adds the Email Campaigns API and related typed models and documentation; no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Application
  participant MailtrapGeneralClient
  participant EmailCampaign
  participant MailtrapAPI
  Application->>MailtrapGeneralClient: emailCampaigns(accountId)
  MailtrapGeneralClient-->>Application: EmailCampaign client
  Application->>EmailCampaign: createEmailCampaign(request DTO)
  EmailCampaign->>MailtrapAPI: POST /api/email_campaigns
  MailtrapAPI-->>EmailCampaign: campaign response
  EmailCampaign-->>Application: handled response
  Application->>EmailCampaign: scheduleEmailCampaign(id, datetime)
  EmailCampaign->>MailtrapAPI: POST /api/email_campaigns/{id}/schedule
  MailtrapAPI-->>EmailCampaign: scheduled campaign response
  EmailCampaign-->>Application: handled response
Loading

Possibly related PRs

  • mailtrap/mailtrap-php#39: Adds a related account-scoped email-management API with DTOs, examples, client mapping, and tests.

Suggested reviewers: mklocek, vladimirtaytor

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: adding the Email Campaigns API.
Description check ✅ Passed The description covers motivation, changes, testing steps, and implementation details; only the non-critical Images and GIFs section is omitted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Rabsztok
Rabsztok marked this pull request as ready for review July 30, 2026 12:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 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/email-campaigns/all.php`:
- Around line 58-71: Update the example flow around createEmailCampaign and all
dependent operations to extract and reuse the created campaign ID from response
data instead of hard-coded 4567. Check the create response for failure and stop
before update, lifecycle, stats, or delete actions when creation does not
succeed; preserve the existing operation order and output behavior for
successful creation.
- Around line 173-181: Update the campaign lifecycle sequence around
resetEmailCampaign so resetEmailCampaign is called while the campaign remains
scheduled. Move the reset demonstration immediately after scheduling, then
schedule the campaign again before the cancellation, start, and termination
steps, or use a separate campaign identifier for the later sequence.
- Line 60: Update the email campaign configuration around mailsendDomainId and
the related contact list/segment IDs to remove account-scoped hardcoded
fallbacks. Require the corresponding environment or configuration values, or
mark each fallback explicitly as a placeholder that must be replaced before use.
- Around line 16-18: Cast the $_ENV['MAILTRAP_ACCOUNT_ID'] value to an integer
when assigning $accountId, then pass that integer unchanged to
MailtrapGeneralClient::emailCampaigns().
🪄 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: b23572ec-0178-4077-92d2-77e45f57fc88

📥 Commits

Reviewing files that changed from the base of the PR and between aa1e5fc and 5a51fc4.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • README.md
  • examples/README.md
  • examples/email-campaigns/all.php
  • src/Api/General/EmailCampaign.php
  • src/DTO/Request/EmailCampaign/CreateEmailCampaign.php
  • src/DTO/Request/EmailCampaign/EmailCampaignInterface.php
  • src/DTO/Request/EmailCampaign/ReplyTo.php
  • src/DTO/Request/EmailCampaign/TemplateAttributes.php
  • src/DTO/Request/EmailCampaign/UpdateEmailCampaign.php
  • src/MailtrapGeneralClient.php
  • tests/Api/General/EmailCampaignTest.php
  • tests/MailtrapGeneralClientTest.php

Comment thread examples/email-campaigns/all.php Outdated
Comment thread examples/email-campaigns/all.php
Comment thread examples/email-campaigns/all.php Outdated
Comment thread examples/email-campaigns/all.php Outdated
@Rabsztok

Copy link
Copy Markdown
Contributor Author

Addressed all 4 CodeRabbit findings in d7105c4:

  • Reuse the campaign created by the example (Major) — the create step now extracts data.id and every dependent step (get/update/lifecycle/stats/delete) reuses it; the script exits early if creation fails.
  • Move reset while the campaign is still scheduled (Major) — lifecycle reordered to schedule → reset → schedule again → cancel → start → terminate, so each action runs from a valid state.
  • Do not use arbitrary account-scoped identifier fallbacks (Minor) — dropped the hardcoded domain UUID fallback (MAILTRAP_DOMAIN_ID env var is now required and documented inline); contact list/segment IDs are marked as placeholders to replace.
  • Cast MAILTRAP_ACCOUNT_ID to int (Minor) — now (int) $_ENV['MAILTRAP_ACCOUNT_ID'], matching other examples.

Also derived the stats date window at runtime (-30 daystoday) so it covers the just-created campaign instead of a fixed past month.

Verified: full phpunit suite (418 tests) green, psalm clean.

@Rabsztok
Rabsztok marked this pull request as draft July 31, 2026 11:56
@Rabsztok
Rabsztok force-pushed the MT-22401-php-email-campaigns branch 2 times, most recently from 9dd3c92 to 2c88691 Compare August 7, 2026 06:23
@Rabsztok
Rabsztok marked this pull request as ready for review August 7, 2026 07:24
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

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.

Comment thread CHANGELOG.md Outdated
Decisions:
- Request bodies are flat JSON — no ['email_campaign' => ...] wrapper; domain_id is an integer sending domain ID
- Single-campaign and stats responses documented/tested as {data: ...} envelopes; delete returns 204 with no body
- Typed TemplateAttributes (subject/body_html/body_text/merge_tags, no template id) and ReplyTo DTOs replace raw arrays
- contact_list_ids/contact_segment_ids kept behind the !== null filter so [] still clears the audience
- Five lifecycle endpoints (start/schedule/cancel/terminate/reset); schedule accepts string or DateTimeInterface; stats gains optional start_date/end_date
Decisions:
- Reuse the created campaign ID across all dependent example steps; exit early when creation fails
- Reorder lifecycle to schedule -> reset -> schedule again -> cancel -> start -> terminate so every action runs from a valid state
- Require MAILTRAP_DOMAIN_ID (no arbitrary fallback) and mark contact list/segment IDs as placeholders
- Cast MAILTRAP_ACCOUNT_ID to int (strict_types + int param)
- Derive stats date window at runtime instead of fixed dates
@Rabsztok
Rabsztok force-pushed the MT-22401-php-email-campaigns branch from 2c88691 to 2d58775 Compare August 10, 2026 07:27
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:
- "/api/accounts/{account_id}/email_campaigns" does not exist, so comments and
  tests should not contrast the real path against it
- The positive path assertions already cover what these comments described
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
@Rabsztok
Rabsztok merged commit 01cf980 into main Aug 14, 2026
22 checks passed
@Rabsztok
Rabsztok deleted the MT-22401-php-email-campaigns branch August 14, 2026 07:07
@github-actions github-actions Bot mentioned this pull request Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants