Fixes the coupling tracked in QRun-IO/qbit-marketing#13: consumers import qbit-email internals, which guardrail G1 forbids.
com.kingsrook.qbits.email.api (the objectstorage.api precedent): EmailApi.isInstalled, send(EmailApiRequest) → EmailApiResult (QUEUED/DUPLICATE/SUPPRESSED/REFUSED + reasons), ensureTemplate(EmailApiTemplate), getMessage(id) and findMessagesByIdempotencyKeyPrefix (ids, status, category, keys, template, linked record and dates only; never addresses, subjects or bodies), listSenderAddresses, defaultProviderName, readiness(qInstance, category) (plain reasons, no secret values).
Own DTOs; a reflection test asserts no public or protected member of the api package exposes an internal qbit-email type.
README "Sending from another qbit" and DESIGN 2.5: route 1 is core-only (SendMessageAction, provider qbitEmail), route 2 is this package; internal packages are not API.
Companion PRs: QRun-IO/qbit-bom#12 (default G1 allow-list for this package), an additive core messaging PR (rich SendMessageInput/Output so send-only consumers need no qbit-email dependency), then the consumer switches.
Also folds #12's EmailEffects into the same surface: EmailApi.sendOnce(request, effectKey) (EmailApiEffectOutcome, EmailApiEffectResult), getMessageByIdempotencyKey, getMessageByRfcMessageId, rfcMessageId on EmailApiMessage. EmailEffects stays as an internal, deprecated delegate; docs/DURABLE-JOBS.md points at EmailApi.
Tests: 287, all green; API coverage 99.2%, overall 95.1%; Checkstyle clean.
Fixes the coupling tracked in QRun-IO/qbit-marketing#13: consumers import qbit-email internals, which guardrail G1 forbids.
- **`com.kingsrook.qbits.email.api`** (the objectstorage.api precedent): `EmailApi.isInstalled`, `send(EmailApiRequest)` → `EmailApiResult` (QUEUED/DUPLICATE/SUPPRESSED/REFUSED + reasons), `ensureTemplate(EmailApiTemplate)`, `getMessage(id)` and `findMessagesByIdempotencyKeyPrefix` (ids, status, category, keys, template, linked record and dates only; never addresses, subjects or bodies), `listSenderAddresses`, `defaultProviderName`, `readiness(qInstance, category)` (plain reasons, no secret values).
- Own DTOs; a reflection test asserts no public or protected member of the api package exposes an internal qbit-email type.
- README "Sending from another qbit" and DESIGN 2.5: route 1 is core-only (`SendMessageAction`, provider `qbitEmail`), route 2 is this package; internal packages are not API.
- Companion PRs: QRun-IO/qbit-bom#12 (default G1 allow-list for this package), an additive core messaging PR (rich SendMessageInput/Output so send-only consumers need no qbit-email dependency), then the consumer switches.
Also folds #12's EmailEffects into the same surface: `EmailApi.sendOnce(request, effectKey)` (EmailApiEffectOutcome, EmailApiEffectResult), `getMessageByIdempotencyKey`, `getMessageByRfcMessageId`, `rfcMessageId` on EmailApiMessage. EmailEffects stays as an internal, deprecated delegate; docs/DURABLE-JOBS.md points at EmailApi.
Tests: 287, all green; API coverage 99.2%, overall 95.1%; Checkstyle clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes the coupling tracked in QRun-IO/qbit-marketing#13: consumers import qbit-email internals, which guardrail G1 forbids.
com.kingsrook.qbits.email.api(the objectstorage.api precedent):EmailApi.isInstalled,send(EmailApiRequest)→EmailApiResult(QUEUED/DUPLICATE/SUPPRESSED/REFUSED + reasons),ensureTemplate(EmailApiTemplate),getMessage(id)andfindMessagesByIdempotencyKeyPrefix(ids, status, category, keys, template, linked record and dates only; never addresses, subjects or bodies),listSenderAddresses,defaultProviderName,readiness(qInstance, category)(plain reasons, no secret values).SendMessageAction, providerqbitEmail), route 2 is this package; internal packages are not API.Also folds #12's EmailEffects into the same surface:
EmailApi.sendOnce(request, effectKey)(EmailApiEffectOutcome, EmailApiEffectResult),getMessageByIdempotencyKey,getMessageByRfcMessageId,rfcMessageIdon EmailApiMessage. EmailEffects stays as an internal, deprecated delegate; docs/DURABLE-JOBS.md points at EmailApi.Tests: 287, all green; API coverage 99.2%, overall 95.1%; Checkstyle clean.
🤖 Generated with Claude Code