# Mailing links custom tracker

This extension allows replacing links in Outreach outbound emails with links provided by your service.
Links your service provide are expected to eventually redirect to the original link. Outreach will call the registered
URL of your service and provide a list of links from the email in the payload expecting to collect the list of replacement
links to be inserted back into the email.

Expect traffic!
Note that on busy customers the traffic rate may become high, thus you should ensure your service can handle that type of load.
If your service becomes unavailable or fails to respond to the request the email will be sent with the set of original links
and the operation will not be retried.

Only `http://` and `https://` links are offered for replacement (other links e.g. `mailto://` are filtered out).

## Configuring mailing links custom tracker extension

Add the "Mailing clicks custom tracker" feature to your app.

![Custom link tracker extension](/assets/mailing-links-feature.38702834460627033cb68660ca2fcd0098139f3da59facdfa4c4ddef64d43037.9c1bb791.png)

Then configure your service URL and optional filter for links to be sent for replacement.

![Custom link tracker extension configuration](/assets/mailing-links-config.46ba5d4a379ad1cecdf08acc16e7e42f5748afd9b4bb215a8903559df385b3e8.9c1bb791.png)

In case the filter is empty the service will receive all `http://` and `https://` links present in the email for replacement.
Otherwise only links that match a specified regular expression will be included into payload. Outreach uses Perl Compatible Regular Expressions syntax.

There is a tester tool present at the configuration page for convenience. It is recommended to verify that the filter is correctly specified
before saving the Mailing links custom tracker configuration by testing it against a sample link value that would be present in the emails.

## Request scenarios

Outreach sends mailing links requests in two different scenarios, depending on where the email is composed. The shape of the
request payload is the same in both cases (see [Request payload format](#request-payload-format)), but the timing and
completeness of the data you receive differs.

### Mailing composed in the Outreach web client

When a mailing is created in the Outreach web client, Outreach has enough time before the send to iterate over every application
with the Mailing links custom tracker installed for the organization and resolve all links in one pass. This link exchange is
part of the background processing that happens before the email leaves Outreach and is invisible to the user. Because of this,
each request contains the complete, final set of links for the mailing.

### Mailing composed in the Gmail extension

When a mailing is composed using the Gmail extension, the Outreach code runs in a much more constrained environment and cannot
start fanning out remote calls the moment the user clicks send. Instead, links are resolved incrementally, as they are added to
or edited in the message body:

- Each time a block of links is inserted, or an existing link is edited, Outreach sends a request containing only those links,
tagged with the same `meta/mailing/id` for the mailing being composed.
- Prospect information is included only when it is known at the time of the request. Because a user can edit the message body
before adding a recipient, or change recipients multiple times while composing, requests carrying the same `meta/mailing/id`
may reference different prospects, or omit prospect information entirely.
- No single request contains the full set of links for the mailing. You can accumulate the links you have seen for a given
`meta/mailing/id` across multiple requests, but you still have no guarantee that they were all part of the email that was
eventually sent, since the user could remove a link after it was already resolved.
- Whether and when the email was actually sent is not reported to your service. If the email is sent, the mailing placeholder is
converted into a real mailing record, usually within a few minutes, and you can then retrieve the final list of recipients from
the [Mailing API](https://developers.outreach.io/api/reference/mailing). There is no notification when this happens, so your
service needs to poll for it if the recipient list matters to you.


## Request payload format

Outreach makes an HTTP POST request to each service URL of applications with the Mailing links custom tracker installed for the
organization, using the following payload:


```json
{
  "data": [
    "https://bit.ly/33zYFqH",
    "https://yhoo.it/35tPtX6"
  ],
  "meta": {
    "mailing": {
      "id": "123"
    },
    "completeness": "full",
    "prospect": {
      "email": "abc@prospect.com",
      "id": "456"
    },
    "user": {
      "email": "def@user.com",
      "id": "789"
    },
    "urls": {
      "https://www.google.com/": "https://bit.ly/33zYFqH",
      "https://www.yahoo.com/": "https://yhoo.it/35tPtX6"
    }
  }
}
```

The `data` array constains either the original links present in the outgoing email or their replacements as per responses from
the services that were called before.

The `meta/urls` object complements the `data` values by providing a mapping between original links extracted from the email to their
most recent replacements.

The `meta/completeness` field indicates whether `data` contains the full set of links for the mailing or only a subset resolved
so far:

- `full` — `data` contains every link for the mailing. This is always the case for mailings composed in the Outreach web
client, since Outreach can resolve every link before making any request.
- `partial` — `data` contains only the links that Outreach was able to resolve at the time of this particular request. This
value only occurs for mailings composed in the Gmail extension, as described in [Request scenarios](#request-scenarios). Do not
assume that a `partial` request will eventually be followed by a `full` one for the same mailing.


Please note that the regular expression filter is applied to the original links and not their replacement values.

In case an organization has multiple applications with Mailing links custom tracker installed the order of the services
being called is not deterministic and can not be relied on.

The `meta/mailing`, `meta/prospect` and `meta/user` objects provide information about the outgoing email.

### Request origin verification

Every mailing links request will contain the `Outreach-Webhook-Signature` header. Use this header to validate that the
request came from Outreach. The signature generation process is described in [application lifecycle webhooks](/client-extensions/app-lifecycle-webhooks).
The secret used to sign mailing links extension payload is the same as for webhook requests.

## Response format

The mailing links extension service is expected to respond with the following JSON:


```json
{
  "data" : {
    "https://bit.ly/33zYFqH" : "https://example.com/aX2",
    "https://yhoo.it/35tPtX6" : "https://example.com/fsr"
  }
}
```

Note that you have to use the **values** from the `data` array as keys for response `data` object. Outreach will only replace URLs that are mapped to valid HTTP(S) URLs; missing or invalid
URLs will be left untouched.

## Service requirements

Outreach gives each mailing links extenion service 2 seconds to respond with valid JSON and it does not retry on any kind of failure.