# Salesforce Marketing Cloud

Utilisez ce connecteur lorsque vous souhaitez que The Wallet Crew envoie **des e-mails transactionnels** via **Salesforce Marketing Cloud**, tandis que Salesforce Marketing Cloud reste l'endroit où votre marque gère les ressources e-mail, le suivi et les rapports.

Cette intégration utilise le **fournisseur d'e-mail script**. The Wallet Crew déclenche l'envoi. Votre script transfère l'événement à Salesforce Marketing Cloud.

## Comment cela fonctionne

The Wallet Crew appelle votre implémentation de `runtime.scriptable.emailEngine.SendEmail`. Votre script appelle ensuite l'API REST de Salesforce Marketing Cloud pour déclencher un événement (en utilisant un `EventDefinitionKey`). Salesforce Marketing Cloud utilise cette charge utile d'événement pour rendre et envoyer l'e-mail.

Ce modèle évite la duplication des modèles. Salesforce Marketing Cloud possède le modèle. The Wallet Crew n'envoie que les variables dont Salesforce Marketing Cloud a besoin, comme l'URL de téléchargement de la carte (Pass) et le libellé CTA localisé.

Si vous n'avez pas encore configuré le fournisseur de script, commencez par [Extensibilité EmailSender](https://app.gitbook.com/s/WLc8AHXW4tdrAXUBfrYF/connect/custom-connector/emailsender-extensibility).

## Avant de commencer

Vous avez besoin de trois choses :

* Un **Installed Package** Salesforce Marketing Cloud capable d'appeler des API REST (client id + client secret).
* Une ressource Salesforce Marketing Cloud qui peut être **déclenchée par API**, exposant un `EventDefinitionKey`.
* Un identifiant stable dans votre payload d'e-mail The Wallet Crew (exemple : `id.customerId`) pour générer l'URL de la carte (Pass).

## Configuration requise dans Salesforce Marketing Cloud

Dans Salesforce Marketing Cloud, créez un point d'entrée déclenché par API et le contenu d'e-mail associé.

1. Créez un **Installed Package** et conservez le **Client Id** et **Client Secret**.
2. Créez la ressource d'envoi que vous souhaitez déclencher (généralement un événement d'entrée de parcours ou un événement API), puis copiez son `EventDefinitionKey`.
3. Assurez-vous que votre modèle d'e-mail Salesforce Marketing Cloud attend les mêmes noms de variables que vous enverrez dans `Données`.

{% hint style="info" %}
La configuration de Salesforce Marketing Cloud varie selon la configuration du compte et l'ensemble de fonctionnalités. Gardez votre contrat de payload stable : les noms de champs dans `Données` doivent correspondre à ce que votre ressource Salesforce Marketing Cloud attend.
{% endhint %}

## Activez Salesforce Marketing Cloud dans The Wallet Crew

Définissez le fournisseur sur `script` afin que The Wallet Crew appelle votre `SendEmail` implémentation.

{% code title="/server/emails.yml" %}

```yaml
provider:
  type: script
resources:
  - /locales/emails/
```

{% endcode %}

### Exemple de script (déclencher un événement Salesforce Marketing Cloud)

Cet exemple déclenche un événement Salesforce Marketing Cloud en utilisant le point de terminaison REST `interaction/v1/events`. Il envoie un titre localisé, un libellé CTA localisé et une URL de Pass Wallet Crew construite à partir d'un identifiant client.

{% hint style="warning" %}
Cette implémentation délègue le rendu à Salesforce Marketing Cloud. Le `buildEmail()` callback de The Wallet Crew n'est intentionnellement pas utilisé.
{% endhint %}

{% code title="Exemple Salesforce Marketing Cloud (implémentation SendEmail)" %}

```javascript
const CUSTOM_DOMAIN = "wallet.brand.com";
const TENANTID = "brand";
const SMFC_DOMAIN = "xxx";

/**
 * @typedef {Object} EmailData
 * @property {string} Subject - Ligne d’objet rendue.
 * @property {string} Body - Contenu du corps rendu.
 */

/**
 * Envoyer un e‑mail en utilisant le nom de modèle et les données fournis.
 * L’appelant fournit les cultures prises en charge et un rappel
 * pour construire le contenu de l’e‑mail rendu.
 *
 * @param {string} recipient - Adresse e‑mail cible.
 * @param {string} emailTemplate - Nom du modèle à rendre.
 * @param {Object.<string, any>} data - Données du modèle passées au script.
 * @param {string[]} cultures - Noms des cultures disponibles fournis par le fournisseur de cultures.
 * @param {(templateName: string) => Promise<EmailData>} buildEmail
 * Rappel qui retourne le contenu final de l’e‑mail rendu.
 *
 * @returns {Promise<void>}
 */
async function sendEmail(recipient, emailTemplate, data, cultures, buildEmail){

  const customerId = data["id.customerId"];
  const url = `https://${CUSTOM_DOMAIN}/${TENANTID}/pass?id.customerId=${customerId}`;  

  const locales = {
    "en": {
      title: "🎉 Your Account is Ready – Add Your Pass to Wallet!",
      label: "Add to Wallet"
    },
    "fr": {
      title: "🎉 Votre compte est prêt – Ajoutez votre pass au Wallet !",
      label: "Ajouter au Wallet"
    }
  };

  const locale = locales[cultures[0]];

  const response = await fetch(`https://${SMFC_DOMAIN}.rest.marketingcloudapis.com/interaction/v1/events`,  {
    Method : "POST", 
    Authentication : {
        mode : 'OAuth2.0', 
        grantType : 'clientCredentials',
        accessTokenUrl : `https://${SMFC_DOMAIN}.auth.marketingcloudapis.com/v2/token`, 
        sendCredentialsAsFormParams: true,
        clientId: await getSecret('SFMC-CLIENTID'), 
        clientSecret : await getSecret('SFMC-CLIENTSECRET')
    }, 
    Headers: {
      "Content-Type": "application/json",
    },
    Body: {
      "ContactKey": recipient,
      "EventDefinitionKey": "confirmationCompteNeostore",
      "Data": {
          "SubscriberKey": recipient,
          "EmailAddress": recipient,
          "Title": locale.title,
          "Url": url,
          "LabelCTA": locale.label,
      }
    }
  });
  const responseData = JSON.parse(response.ResponseText); 
  if(!responseData?.eventInstanceId){
    throw new Error(`error while sending custom email status : ${response.StatusCode} - content : ${response.ResponseText}`)
  }
}

export default function(context) {
  context.register('runtime.scriptable.emailEngine', {
    SendEmail: sendEmail 
  })
}
```

{% endcode %}

### Ce qu'il faut valider

Déclenchez un véritable e-mail transactionnel, puis validez de bout en bout :

* The Wallet Crew appelle votre script sans erreurs.
* L'appel API Salesforce Marketing Cloud retourne un `eventInstanceId`.
* Salesforce Marketing Cloud rend l'e-mail avec `Title`, `Url`, et `LabelCTA`.
* Le CTA ouvre l'URL Wallet Crew et la carte (Pass) peut être installée.

## Dépannage

Si les envois échouent, isolez le problème dans cet ordre :

* **OAuth échoue (401/403)** : l'id/secret client est incorrect, révoqué ou le package installé n'a pas d'accès API.
* **Aucun `eventInstanceId`** : le `EventDefinitionKey` est invalide, non publié ou le schéma de payload est rejeté.
* **Variables vides dans l'e-mail** : le modèle Salesforce Marketing Cloud attend des noms de champs différents de ceux que vous envoyez dans `Données`.
* **Mauvaise langue**: `cultures[0]` ne correspond pas à votre carte de locales. Ajoutez un repli (exemple : par défaut à `en`).

## FAQ

<details>

<summary><strong>Salesforce Marketing Cloud ou The Wallet Crew possède-t-il le HTML de l'e-mail ?</strong></summary>

Salesforce Marketing Cloud possède le HTML dans ce modèle. The Wallet Crew n'envoie que des variables (titre, libellé CTA, URL) afin que votre équipe marketing puisse itérer sur le modèle sans déployer de modifications Wallet Crew.

</details>

<details>

<summary><strong>Pouvons-nous toujours utiliser les modèles Wallet Crew et <code>buildEmail()</code>?</strong></summary>

Oui, mais cela devient une stratégie différente. Dans ce modèle, The Wallet Crew rend `Objet` et `Corps`, et Salesforce Marketing Cloud est uniquement utilisé comme passerelle de livraison. Si vous souhaitez cela, alignez la ressource Salesforce Marketing Cloud pour accepter du HTML rendu et évitez la double mise en modèle.

</details>

<details>

<summary><strong>Où stockons-nous les identifiants SFMC ?</strong></summary>

Stockez-les en tant que secrets du locataire et chargez-les à l'exécution (comme dans l'exemple avec `getSecret('SFMC-CLIENTID')` et `getSecret('SFMC-CLIENTSECRET')`). Ne codez pas les identifiants en dur dans les scripts.

</details>

<details>

<summary><strong>Que devons-nous utiliser comme <code>ContactKey</code>?</strong></summary>

Utilisez un identifiant de contact Salesforce Marketing Cloud stable. De nombreuses marques utilisent l'adresse e-mail, mais vous pouvez également utiliser un identifiant CRM si c'est votre stratégie de clé de contact Salesforce Marketing Cloud. Gardez-le cohérent avec la façon dont votre parcours/ressource résout les destinataires.

</details>
