@expertum/cap-email-plugin
Sends mail on entity lifecycle events from an annotation — @email.enabled on an entity, an HTML template with {{placeholder}} substitution, and a plugin-owned log entity recording what went out and what failed.
The dispatcher is swappable through cds.requires.kinds, and the Microsoft Graph provider authenticates through the BTP Destination Service rather than holding credentials itself. Triggers are INSERT and UPDATE, so it covers "tell someone this record changed" without a handler.
Facts
Where it sits
Who is behind it
In the atlas: maintains 1@expertum-netStijn MertensStijn MertensMaintains this
In the atlas: maintains 1, contributes to 1@stijnmemaintainersMatthis VansteenhuyseContributes to this
In the atlas: contributes to 1@MVansteenhuyse1 contributor
Before choosing this
Conditions
LicenceSAP Developer License Agreement 3.2 CAP§ 1, 2, 3A cds-plugin is used with SAP CAP materials, or an artifact is explicitly identified as a CAP plugin or application.
- § 1 License. Productive customer applications are limited to SAP BTP or another SAP-licensed platform, and mass extraction to a non-SAP product is restricted except where solely required for SAP interoperability.
- § 2 Intellectual Property. The agreement retains SAP's rights in the covered materials and limits making APIs, tools or software available to third parties, while preserving ownership of customer applications subject to SAP's underlying rights.
- § 3 Artificial Intelligence Training. The agreement prohibits use of the covered materials and customer applications for training artificial-intelligence models or systems.
PracticalFunctional boundary
Node below 22, or @sap/cds@sap/cdsThe CAP Node.js runtime, which compiles the CDS model, serves the services declared in it, answers generic requests before any handler runs, and loads every cds-plugin.sap official, cap below 9: the package declares the first in engines and the second as a peer dependency. Any mail path other than Microsoft Graph, until a provider is written for it: graph is the only kind that sends, and basic, the kind configured by default, is the base class such a provider extends.
What it declares
Every artifact
- Type
- CDS plugin
- Origin
- Independently maintained
- Runtime
- Node.js
As a CDS plugin
- Declared for
- >=9
- Distributed through
- npm
Connections
Telling a person something happened when they are not looking
HTTP client carrying a destination's credentials
Named, credentialed addresses of other systems resolved at runtime
Download
Install
npm add @expertum/cap-email-pluginDerived from the package name. No recipe recorded; the README has the configuration.
Where it sits in your app
Download
README
quoted from expertum-net/cap-email-plugin under Apache-2.0, read@expertum/cap-email-plugin
A SAP CAP plugin that provides annotation-driven email automation for CAP entities. Emails are triggered on entity lifecycle events (INSERT, UPDATE) and dispatched via configurable email clients.
Features
- Annotation-based configuration — no custom handler code required
- Automatic trigger handling — emails sent on entity INSERT/UPDATE
- Template support — HTML templates with
{{placeholder}}substitution - BTP integration — leverages Destination Service for OAuth2 authentication
- Extensible architecture — swappable email clients via
cds.requires.kinds - Email logging — plugin-owned log entity tracks send status and errors
Prerequisites
- SAP CAP (
@sap/cds>= 9) - Node.js >= 22 (required for ESM +
@cap-js/cds-testcompatibility) - BTP Destination Service (for Microsoft Graph provider)
Installation
npm install @expertum/cap-email-plugin
Quick Start
1. Annotate your entity
@email.enabled: true
entity Orders {
key ID : UUID;
orderNumber : String;
status : String;
contactEmail: String;
}
That's it for a minimal setup. The plugin defaults to:
- Template:
Orders.html(convention-based on entity name) - Trigger:
INSERT - Recipient:
req.user.email(from XSUAA context)
2. Create a template
Place an HTML template in your project:
email-templates/Orders.html
<h1>Order Confirmation</h1>
<p>Your order {{orderNumber}} has been received.</p>
Placeholders use {{fieldName}} syntax, where fieldName matches a field on the annotated entity. When an email is
triggered, the plugin replaces each placeholder with the corresponding value from the entity record. Missing fields are
replaced with an empty string.
3. Configure the email provider
In your application's package.json:
{
"cds": {
"requires": {
"email": {
"kind": "graph",
"email": {
"from": "noreply@example.com",
},
},
},
},
}
The graph kind uses Microsoft Graph API via a BTP destination. Configure the destination with OAuth2ClientCredentials
in your BTP subaccount.
{
"cds": {
"requires": {
"email": {
"kind": "graph",
"destination": "microsoft-graph",
"email": {
"from": "noreply@example.com",
},
},
"microsoft-graph": {
"kind": "rest",
"credentials": {
"destination": "your-ms-graph-btp-destination",
},
},
},
},
}
Annotation Reference
All @email properties have sensible defaults. Only specify what you need to override.
| Property | Type | Default | Description |
|---|---|---|---|
enabled | Boolean | false | Activates email for the entity |
template | String | {EntityName} | Template file name (without extension) |
trigger | Array | ['INSERT'] | Lifecycle events: INSERT, UPDATE |
condition | String | (none) | Optional CDS expression for conditional sending |
recipient | String | (none) | Static recipient email address (mutually exclusive with recipientField) |
recipientField | String | (none) | Entity field containing recipient email (mutually exclusive with recipient) |
subject | String | (none) | Subject line (supports {{placeholder}} syntax) |
rollback | Boolean | false | If true, roll back the originating transaction on email failure |
Full annotation example
@email: {
enabled: true,
template: 'order-confirmation',
trigger: ['INSERT', 'UPDATE'],
condition: 'status = ''APPROVED''',
recipientField: 'contactEmail',
subject: 'Order {{orderNumber}} confirmed',
rollback: true
}
entity Orders { ... }
Static recipient example
@email: {
enabled: true,
recipient: 'support@company.com',
subject: 'New support request'
}
entity SupportRequests { ... }
Email Providers
Providers are registered as CAP service kinds. The plugin ships with:
| Kind | Description |
|---|---|
basic | Base email service class |
graph | Microsoft Graph API via cds.connect.to() and BTP Destination Service |
Select your provider in package.json under cds.requires.email.kind.
How It Works
- Entity INSERT/UPDATE triggers an
afterhandler - Plugin evaluates
@emailannotations and optional conditions - Template is loaded from your project and rendered with entity data
- Recipient resolved from
@email.recipient,@email.recipientField, orreq.user.email - Email dispatched asynchronously via the configured provider
- Status logged; failures recorded in the plugin-owned log entity
Emails are sent after successful operations only. Failed transactions never trigger emails. By default, email
failures do not roll back the originating transaction, but this is configurable via @email.rollback.
Plugin Architecture
cds-plugin.ts → Entry point; registers handlers
lib/plugin.ts → Core logic; attaches after handlers for @email entities
lib/basic.ts → Base EmailService class (extends cds.Service)
lib/graph-mail.ts → Microsoft Graph implementation
lib/template-engine.ts → Template loading and {{placeholder}} rendering
Development
npm install
npm test
Test App
A minimal CAP application lives at test/test-app/ for testing the plugin end-to-end. It depends on the plugin via
"file:../../." so changes are picked up immediately without publishing.
test/test-app/
package.json ← plugin dependency + basic kind config
db/schema.cds ← Orders (minimal), Tickets (full), Products (control)
srv/services.cds ← TestService exposing all entities
email-templates/ ← templates for annotated entities
To run the test app standalone:
cd test/test-app
npm install
npx cds serve
Tech Stack
- TypeScript (ESM)
- Node.js >= 22
- oxlint + Prettier
@cap-js/cds-test+@types/jest(jest-style assertions)- Conventional Commits (
feat:,fix:,chore:, etc.)
License
Copyright 2026 Expertum Group Apache-2.0
History
Others providing
Compare all 10 on the Notifications page →- aditheos/ApplicationLogsNotificationToFioriaditheos/ApplicationLogsNotificationToFioriRaises a Fiori launchpad notification when an application log records an error, and the notification opens the Application Logs app (F1487) on that log for review and corrective action.independent, abapFiori launchpad notification for application log errorsfrom ABAP
- agiguere/SCPmsPushNotificationREST_APIagiguere/SCPmsPushNotificationREST_APIABAP classes that send push notifications from an SAP backend to iOS devices through the REST API of SAP Cloud Platform Mobile Services, reached through an RFC destination on NetWeaver 731 or higher.independent, abapABAP classes sending push notifications to Mobile Servicesfrom ABAP
- ABAP-PRCABAP-PRCA framework for custom multi-step ABAP processes: a process class declares the states, and the framework runs each document through them and monitors the run.independent, abapFramework for multi-step ABAP processes with monitoringfrom ABAP
- com.sap.cds:cds-feature-notificationscom.sap.cds:cds-feature-notificationsSends business notifications from a CAP Java application through SAP Alert Notification service, delivered to SAP Build Work Zone or email, or logged to the console in local mode.sap official, capBusiness notifications from CAP Java via SAP Alert Notificationfrom CAP
- @cap-js/notifications@cap-js/notificationsPublishes business notifications to SAP Build WorkZone from the application, so a user is told something happened without the UI polling for it.sap official, capBusiness notifications from CAP to SAP Build WorkZonefrom CAP
- @cap-rp/notifications@cap-rp/notificationsA derived copy of the official notifications plugin under a different scope; its readme is @cap-js/notifications' with the name swapped.independent, capRenamed copy of @cap-js/notifications under another scopefrom CAP
- DryDumbHead/easyHtmlEmailDryDumbHead/easyHtmlEmailA helper class that builds HTML emails in ABAP from an HTML template uploaded through SMW0, with placeholders replaced at runtime, so only the dynamic values are handled in code.independent, abapABAP helper class building HTML emails from templatesfrom ABAP
- @neoimpulse/cap-js-notifications@neoimpulse/cap-js-notificationsA copy of the official @cap-js/notifications plugin republished under another scope, whose README points at the original and says nothing about what was changed.independent, capCopy of @cap-js/notifications published under another scopefrom CAP
- peterlangner/zrsspeterlangner/zrssAn ABAP package that publishes content from an SAP NetWeaver ABAP system as an RSS feed for ABAP Development Tools and other RSS readers, stated for ABAP 7.00 and installed with abapGit.independent, abapRSS feed publisher for content from an SAP NetWeaver ABAP systemfrom ABAP
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
Flavors
“Node.js >= 22 (required for ESM + `@cap-js/cds-test` compatibility)” — @expertum/cap-email-plugin — README
Contributors
History in the atlas
- The repository answers again: the GitHub API returns it created 2026-03-06 and pushed 2026-09-18, and raw.githubusercontent serves its README, its package.json and lib/. Nothing says whether it was private or gone between 2026-09-08 and now.
- Follows the repository being readable again. The declared Apache-2.0 licence and the TypeScript the package is built from are both in it.
- The two version floors, and the provider boundary
- object form, both conditional
- 404 from the GitHub API. Found by the first full run of scripts/check-links.mjs — the citation had a checked date and nobody had re-read it.
- First seen.
For your agent
- Ref
artifact:expertum-cap-email-plugin- JSON
- /artifacts/expertum-cap-email-plugin.json
- MCP
- Connecting an agent