A template is the smallest build that meets a requirement, but it's a starting point, not a finished Connector. This page takes the official email template from a fresh copy to a state you can stage, and shows how to prepare any template for your own environment on the way.
v0.1.0 that is ready for the next page.Prepare your tools
You need the following:
- A Node.js version that Connect supports. See supported runtimes.
- Docker. The Connect CLI uses it to build and validate your application locally.
- A GitHub account for your own repository.
- An API Client for the CLI, as described in the following section.
commercetools --version to confirm that the CLI is available.Create an API Client for the CLI
| Scope | Where this module uses it |
|---|---|
manage_connectors | Stage and publish the Connector (Stage, preview, and publish privately). |
manage_connectors_deployments | Install and operate Deployments (Install and test your Connector and Operate a Deployment). |
manage_api_clients | Deploy a Connector that uses inheritAs (see the warning after the next section). |
manage_orders | Import the test Order that triggers the email (Install and test your Connector). |
manage_subscriptions or view_subscriptions | Check the Subscription that the Connector creates (Install and test your Connector). |
Then sign in:
commercetools auth login --client-credentials \
--client-id <client-id> \
--client-secret <client-secret> \
--project-key <project-key> \
--region <region>
--region. commercetools auth login describes each flag. Keep the client secret out of your repository.Create your repository
--template value is email-integration, which differs from the documentation page name, transactional-emails:commercetools connect init zen-order-confirmation --template email-integration
cd zen-order-confirmation
git init
git add .
git commit -m "Start from the email template"
Create an empty repository in your GitHub account, then push:
git branch -M main
git remote add origin git@github.com:<your-account>/zen-order-confirmation.git
git push -u origin main
package-lock.json file.connect.yaml:zen-order-confirmation/
├── connect.yaml
└── mail-sender/
├── package.json
├── src/
└── tests/
The template is JavaScript, not TypeScript. This module keeps its code in JavaScript.
Read connect.yaml
connect.yaml file at the root of the repository tells Connect what to build and how to run it. The template's file looks like this (abbreviated):deployAs:
- name: mail-sender
applicationType: event
endpoint: /mailSender
scripts:
postDeploy: npm install && npm run connector:post-deploy
preUndeploy: npm install && npm run connector:pre-undeploy
configuration:
standardConfiguration:
- key: CTP_REGION
description: commercetools Composable Commerce API region
securedConfiguration:
- key: CTP_PROJECT_KEY
- key: CTP_CLIENT_ID
- key: CTP_CLIENT_SECRET
- key: CTP_SCOPE
- key: EMAIL_PROVIDER_API_KEY
- key: SENDER_EMAIL_ADDRESS
- key: CUSTOMER_REGISTRATION_TEMPLATE_ID
- key: CUSTOMER_EMAIL_TOKEN_CREATION_TEMPLATE_ID
- key: CUSTOMER_PASSWORD_TOKEN_CREATION_TEMPLATE_ID
- key: ORDER_CONFIRMATION_TEMPLATE_ID
- key: ORDER_STATE_CHANGE_TEMPLATE_ID
- key: ORDER_REFUND_TEMPLATE_ID
description for every key. Configure connect.yaml defines each field. In this template, note the following:namemust match the application's folder,mail-sender.endpointis/mailSender. The Express router inmail-sendermust serve this path, or deliveries never reach the handler. The email integration guide describes this requirement.scriptscreate and delete the template's Subscription.securedConfigurationholds every key exceptCTP_REGION, so the installer can't read those values back after setting them.
Whoever installs a Connector supplies a value for each key. The template asks for 13 values, four of which are an API Client's project key, ID, secret, and scope. The next section removes them.
Generate credentials instead of collecting them
inheritAs.apiClient.scopes setting makes Connect create the API Client at deployment time, with only the scopes you list. Nobody handles a secret.connect.yaml as follows: securedConfiguration:
- - key: CTP_PROJECT_KEY
- description: commercetools Composable Commerce project key
- - key: CTP_CLIENT_ID
- description: commercetools Composable Commerce client ID
- - key: CTP_CLIENT_SECRET
- description: commercetools Composable Commerce client secret
- - key: CTP_SCOPE
- description: commercetools Composable Commerce client scope
- key: EMAIL_PROVIDER_API_KEY
description: The API key used to communicate with email provider
# ...the remaining keys stay as they are...
- key: ORDER_REFUND_TEMPLATE_ID
description: Identifier of order refund email template stored in email service provider
+inheritAs:
+ apiClient:
+ scopes:
+ - manage_subscriptions
+ - view_orders
+ - view_customers
inheritAs is a top-level key, a sibling of deployAs. The connect.yaml file now asks installers for nine values.CTP_* variables that Variables available in the Connect application lists. The template's mail-sender/src/utils/config.utils.js already reads CTP_CLIENT_ID, CTP_CLIENT_SECRET, CTP_PROJECT_KEY, and CTP_SCOPE, so the application code needs no change. The template doesn't read CTP_API_URL or CTP_AUTH_URL. Instead, the template builds both hosts from CTP_REGION, so CTP_REGION stays as a value that the installer enters.manage_subscriptions for the Subscription that postDeploy creates and preUndeploy deletes, view_orders for the Order the confirmation handler retrieves, and view_customers for the Customer. The email integration guide maps each capability to its scope, and notes that flows creating Customer tokens need manage_customers. This module doesn't exercise those flows.manage_api_clients to the CLI's API Client, not to the Connector's inheritAs.apiClient.scopes list. Without it, a Deployment of this Connector fails with 403. See Automatically generate API Client credentials.Validate and update dependencies
commercetools connect validate
.connect/ folder with build and scan logs. Add .connect/ to .gitignore so that you don't commit it.devDependencies doesn't hide its findings. Only updating or removing the package changes the result.mail-sender/package.json:sinon,supertest, andglobalsare listed underdependencies, although only tests use them.mochais listed too, but the tests run on Jest, so nothing uses it.
mocha, move the test packages to devDependencies so that the manifest shows what the application needs at runtime, then apply the available security updates:cd mail-sender
npm uninstall mocha
npm install --save-dev sinon supertest globals
npm audit fix
package.json and running npm install. Commit the updated package-lock.json. Connect installs from it.commercetools connect validate again from the repository root. If the SCA step still fails, run npm audit in mail-sender to see which packages are affected, then update or remove them. If an advisory has no fix available, check whether your code uses the affected package before you decide how to proceed.npm audit and triage any remaining advisories before production use.Treat local SAST as an early warning
Local static application security testing (SAST) can report code smells, such as an empty constructor or high cognitive complexity, that the remote pipeline accepts. The remote pipeline runs when you preview or publish a Connector. Local analysis can be stricter than the remote gate.
Adjust the destination validator for Google Cloud
CONNECT_SUBSCRIPTION_DESTINATION to GoogleCloudPubSub, which is 17 characters. The template's validator in mail-sender/src/validators/env.validators.js accepts at most 10:optional(standardString)(
['connectSubscriptionDestination'],
{
code: 'InvalidSubscriptionDestination',
message: 'Subscription destination is required.',
referencedBy: 'environmentVariables',
},
{ min: 2, max: 10 }
),
postDeploy creates no Subscription, and the running application can't process events. An AWS Region isn't affected, because its destination value, SNS, is 3 characters.Reproduce the failure locally before you change it. The command needs no deployment:
cd mail-sender
npm ci
CTP_CLIENT_ID=aaaaaaaaaaaaaaaaaaaaaaaa \
CTP_CLIENT_SECRET=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb \
CTP_PROJECT_KEY=my-project CTP_REGION=europe-west1.gcp \
CONNECT_SUBSCRIPTION_DESTINATION=GoogleCloudPubSub \
CONNECT_GCP_TOPIC_NAME=event-abc-mail-sender \
CONNECT_GCP_PROJECT_ID=ct-connectors-preview \
node --input-type=module -e "import r from './src/utils/config.utils.js'; r(); console.log('ok')"
statusCode is InvalidEnvironmentVariablesError, and its errors list contains the code InvalidSubscriptionDestination. That entry's message, Subscription destination is required., is misleading: the value is set, but it's longer than the limit. Remove the upper limit. A separate validator, validDestinations, already restricts the value to GoogleCloudPubSub or SNS: { min: 2, max: undefined }
ok.Tag your first release
Commit your changes and tag the release. Connect builds a Connector from a repository URL and a tag, so every version that you stage needs its own tag:
cd ..
git add .
git commit -m "Generate API Client credentials, update dependencies, adjust GCP destination validator"
git tag v0.1.0
git push origin main --tags
v0.1.0 in your repository. It still sends no real email: the template's sendMail method only logs. Implement and test the event app to the contract narrows the Connector to the Messages that Zen Electron sends email for and tests its mapping, and keeps the provider call stubbed so that you don't need a provider account.Other starting points
The email template is one of several ways to start a Connector:
- Other templates.
commercetools connect initaccepts other--templatevalues, whichcommercetools connect initlists. The values don't match the documentation page names, andfulfilment-integrationhas no documentation page. Compare the CLI reference with the templates overview. - An empty application.
commercetools connect application addadds an application to an existing project. - A fork. Fork an open-source Connector when it covers most of your requirement (step 3 of the adoption ladder).
- An existing integration. Convert an existing integration describes how to add
connect.yamlto code that you already run.
Key takeaways
- A template is a starting point. Read, validate, and test it before you build on it, and expect to update its dependencies and configuration for your environment.
- Each
deployAs[].namemust match its folder, and theendpointmust match the path your router serves. inheritAs.apiClient.scopesmakes Connect generate the Connector's API Client with only the scopes you list. The identity that deploys the Connector needsmanage_api_clients.- Software composition analysis scans dependencies and development dependencies, and fails on critical findings. Moving a package to
devDependenciesdoesn't hide it: remove what you don't use and update what's vulnerable. - Local analysis can be stricter than the remote pipeline. Use it as an early warning, and treat the remote report as the gate for preview and publish.
- A Deployment that reports success can still create no Subscription. In a Google Cloud Region, the template's destination validator rejects
GoogleCloudPubSubuntil you remove the length limit. - Updating the SDK packages to their current versions is a sensible follow-up. This module leaves it out to keep the tested path stable.