Skip to content

MT-22401: Add email campaigns API - #27

Merged
Rabsztok merged 4 commits into
mainfrom
MT-22401-go-email-campaigns
Aug 14, 2026
Merged

MT-22401: Add email campaigns API#27
Rabsztok merged 4 commits into
mainfrom
MT-22401-go-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 Go SDK.

Changes

  • Add EmailCampaignsService covering the full contract: list (page-token pagination + search filter, plus an All iterator), get, create, update, delete (204), the five lifecycle actions (Start, Schedule, Cancel, Terminate, Reset), and Stats with an optional date range
  • Models follow the published OpenAPI schema: flat request bodies, data-envelope unwrapping, domain_id as int64 (matching Sending Domains ids), 10-value state consts, audience id lists, template body_html/body_text/merge_tags
  • Runnable walkthrough in examples/email-campaigns/main.go + README "Email marketing" section

How to test

  • Run examples/email-campaigns/main.go with a real API token and a verified sending domain — create a draft, update design/audience, schedule + cancel, fetch stats, delete
  • Verify list pagination tokens round-trip (All walks past page 1 on an account with >50 campaigns)

Summary by CodeRabbit

  • New Features

    • Added email campaign management, including creating, updating, deleting, scheduling, starting, canceling, terminating, and resetting campaigns.
    • Added campaign listing with search, pagination, and iteration across all results.
    • Added campaign details and performance statistics, with optional date filtering.
    • Added an end-to-end email campaign example covering the full campaign lifecycle.
  • Documentation

    • Added email marketing and email campaign examples to the supported functionality guide.

@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: 97b388de-fbcd-4930-9e48-51b65878520e

📥 Commits

Reviewing files that changed from the base of the PR and between 75f486c and 32755a7.

📒 Files selected for processing (2)
  • email_campaigns.go
  • examples/email-campaigns/main.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • email_campaigns.go

📝 Walkthrough

Walkthrough

Changes

The client now exposes an initialized EmailCampaignsService with typed campaign models and operations for CRUD, pagination, lifecycle actions, and statistics. Tests cover API requests and response mapping. An example demonstrates the campaign lifecycle, and the README documents email campaign support.

Email campaigns

Layer / File(s) Summary
Campaign contracts and options
client.go, email_campaigns.go
Defines campaign models, lifecycle constants, request payloads, pagination types, delivery settings, templates, and statistics types.
Campaign service and client wiring
client.go, email_campaigns.go
Initializes the service and implements listing, iteration, CRUD, lifecycle actions, and statistics requests.
Campaign API validation
email_campaigns_test.go
Validates endpoint paths, query and body encoding, pagination, response mapping, lifecycle metadata, deletion, and statistics.
Campaign example and documentation
examples/email-campaigns/main.go, README.md
Adds a campaign lifecycle example and documents email campaign support.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: ⚪ Minimal · up to 32755

The PR adds a localized public example and API surface; no actionable merge-blocking risk remains beyond normal checks and review.

Possibly related PRs

  • mailtrap/mailtrap-go#21: Extends the Go SDK with related Email Marketing API services, examples, and README entries.

Suggested reviewers: igordobryn, leonid-shevtsov

Sequence Diagram(s)

sequenceDiagram
  participant Application
  participant EmailCampaignsService
  participant MailtrapAPI
  Application->>EmailCampaignsService: Create or update campaign
  EmailCampaignsService->>MailtrapAPI: Send campaign request
  MailtrapAPI-->>EmailCampaignsService: Return campaign data
  Application->>EmailCampaignsService: Schedule, start, or retrieve statistics
  EmailCampaignsService->>MailtrapAPI: Send action or stats request
  MailtrapAPI-->>Application: Return typed campaign or statistics
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 addition of the Email Campaigns API to the Go SDK.
Description check ✅ Passed The description covers the motivation, changes, and testing steps; only the non-critical Images and GIFs section is missing.
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 `@email_campaigns_test.go`:
- Around line 137-141: Update the template assertions in the test to fail
immediately when c.Template is nil before dereferencing it. Keep the existing
field validation for non-nil templates, and ensure the BodyText assertion runs
only after the template has been safely validated.

In `@email_campaigns.go`:
- Around line 178-182: Update ContactListIDs and ContactSegmentIDs to use a
presence-aware representation so nil means unchanged while an explicitly empty
slice serializes and clears the full audience; preserve JSON field names and
existing non-empty behavior.

In `@examples/email-campaigns/main.go`:
- Around line 23-29: Update the campaign configuration around the fixed
contact-list IDs and the mailtrap.EmailCampaignReplyTo value to read
account-specific audience and reply-to settings from environment variables,
including replacing hardcoded IDs 55 and 56. Ensure ReplyTo is omitted when its
configuration is unset, and avoid using the unrelated hardcoded acme.com domain.
- Line 56: Update the scheduling call in the EmailCampaigns example to build the
timestamp at runtime using a future UTC time instead of the fixed date literal.
Ensure the generated value is reliably in the future when passed to Schedule.
🪄 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: f7b6d101-c955-45e3-bcb3-7c2bdb5f5017

📥 Commits

Reviewing files that changed from the base of the PR and between e41eb2c and 6a4f1c3.

📒 Files selected for processing (5)
  • README.md
  • client.go
  • email_campaigns.go
  • email_campaigns_test.go
  • examples/email-campaigns/main.go

Comment thread email_campaigns_test.go Outdated
Comment thread email_campaigns.go Outdated
Comment thread examples/email-campaigns/main.go Outdated
Comment thread examples/email-campaigns/main.go Outdated
@Rabsztok

Copy link
Copy Markdown
Contributor Author

Addressed the CodeRabbit review findings in c769077:

  • Preserve explicit empty audience updates (email_campaigns.go): ContactListIDs/ContactSegmentIDs on UpdateEmailCampaignRequest are now *[]int64nil is omitted (audience unchanged), while &[]int64{} serializes as [] and clears the full set, per the API's full-set semantics. Added TestEmailCampaigns_UpdateClearAudience proving [] is sent and nil is omitted.
  • Parameterize account-specific campaign settings (examples/email-campaigns): the contact list ID now comes from MAILTRAP_CONTACT_LIST_ID (same convention as the other examples); the hardcoded acme.com ReplyTo was removed.
  • Runtime schedule timestamp (examples/email-campaigns): the schedule time is now derived at runtime as now + 24h UTC.
  • Panic-prone template assertion (email_campaigns_test.go): the Get test now fails fast with t.Fatalf when Template is nil before dereferencing it.

go vet ./..., go test -race ./..., and golangci-lint run all pass.

@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.

🧹 Nitpick comments (1)
email_campaigns_test.go (1)

226-239: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add symmetric coverage for segment clearing.

This test proves that ContactListIDs: &[]int64{} serializes as [] and that a nil ContactSegmentIDs is omitted. It does not prove that ContactSegmentIDs: &[]int64{} also serializes as []. Add a matching test or subtest for the segment field.

🤖 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 `@email_campaigns_test.go` around lines 226 - 239, Extend
TestEmailCampaigns_UpdateClearAudience with a matching case for
ContactSegmentIDs: use an explicitly empty slice, assert the PATCH body contains
{"contact_segment_ids": []}, and keep ContactListIDs nil so it remains omitted.
Reuse the existing client update flow and handler pattern to verify symmetric
clearing behavior.
🤖 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 `@email_campaigns_test.go`:
- Around line 226-239: Extend TestEmailCampaigns_UpdateClearAudience with a
matching case for ContactSegmentIDs: use an explicitly empty slice, assert the
PATCH body contains {"contact_segment_ids": []}, and keep ContactListIDs nil so
it remains omitted. Reuse the existing client update flow and handler pattern to
verify symmetric clearing behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c5730c9-d5dc-40f9-a55c-052d5f172347

📥 Commits

Reviewing files that changed from the base of the PR and between 6a4f1c3 and c769077.

📒 Files selected for processing (3)
  • email_campaigns.go
  • email_campaigns_test.go
  • examples/email-campaigns/main.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/email-campaigns/main.go
  • email_campaigns.go

@Rabsztok
Rabsztok marked this pull request as draft July 31, 2026 11:56
Decisions:
- Request bodies are flat (no email_campaign wrapper) per the current API contract
- Single-object and stats responses unwrap {data: ...} via local anonymous wrapper structs (webhooks.go precedent)
- Delete returns (*Response, error) since the API responds 204 No Content
- Lifecycle endpoints (start/schedule/cancel/terminate/reset) share a private action helper with a body param for schedule
- List returns a public page struct with *int prev/next tokens plus an All iter.Seq2 iterator (email_logs.go precedent)
Decisions:
- Audience fields on UpdateEmailCampaignRequest become *[]int64 (tri-state):
  nil is omitted so partial updates stay partial, while a pointer to an
  empty slice serializes as [] to clear the full audience set, matching
  the API's "treated as the full set" semantics
- Example reads the contact list ID from MAILTRAP_CONTACT_LIST_ID (repo
  env-var convention), drops the hardcoded acme.com ReplyTo, and derives
  the schedule time at runtime (now + 24h UTC)
- Get test fails fast on nil Template instead of dereferencing it
@Rabsztok
Rabsztok force-pushed the MT-22401-go-email-campaigns branch from c769077 to ddac44d Compare August 6, 2026 12:06
@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.

@Rabsztok Rabsztok changed the title MT-22401: Add email campaigns service MT-22401: Add email campaigns API Aug 10, 2026
Decisions:
- Rename EmailCampaignsPagination to Pagination; nothing in it is campaign-specific
- Move it beside Response in client.go, where shared response plumbing lives
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 3c92eed into main Aug 14, 2026
4 checks passed
@Rabsztok
Rabsztok deleted the MT-22401-go-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