Amazon SES ses:custom-path shipped 14 August 2026 - and the AWS deep link example uses Apple's legacy AASA format

SES ses:custom-path lets tracked email links open your app, but the AWS AASA example is the legacy format and bad values fail silently.

Read time
13 min
Word count
2.1K
Sections
10
FAQs
8
Share
Amazon SES ses:custom-path deep link tracking URL change from CL0 to CL1, August 2026
SES click-tracking URLs gain a matchable path segment for iOS and Android deep links.
On this page · 10 sections
  1. What actually changed
  2. The AASA example is the legacy format
  3. Android does not read the path from the JSON file at all
  4. Your analytics will not tell you which links were deep-linkable
  5. How to tell if this affects you
  6. India-specific considerations
  7. What is still unknown
  8. FAQ
  9. How eCorpIT can help
  10. References

Summary. On 14 August 2026 Amazon SES added the ses:custom-path HTML attribute, which inserts a fixed path segment into click-tracking URLs so iOS Universal Links and Android App Links can match them. The tracking URL changes from /CL0/{encodedUrl}/{index}/{messageId}/{hmac} to /CL1/{yourpath}/{encodedUrl}/{index}/{messageId}/{hmac}. The value must be 1-32 characters, case-sensitive, drawn from letters, digits, hyphens, periods and the _ character. Three things the announcement does not tell you: an invalid value falls back to the default /CL0/ format with no error, the AWS example apple-app-site-association file uses Apple's legacy paths array rather than the current components array, and the path never appears in click event data. SES is available in the 3 pricing tiers documented in the SES Developer Guide, and open and click metrics are retained for 60 days.

For 5 years the practical answer to "can we track email clicks and still open the app?" has been no. Click tracking rewrites every <a href> to a redirect domain, and both mobile platforms decide which app opens a URL by matching the host and the path prefix against a verification file. A rewritten URL with an opaque path matched nothing, so the link opened Safari or Chrome instead of the app. Teams disabled click tracking, or accepted the browser bounce, or ran a second redirect service alongside SES.

ses:custom-path closes that gap. It is a small attribute with a large blast radius, because getting it wrong produces a link that works perfectly in a browser and silently never opens the app.

What actually changed

The attribute goes on individual anchor tags in the email HTML:

View product

SES strips the attribute before delivery, so recipients never see it. What they receive is a link to your custom redirect domain carrying the segment you specified. The AWS SES Developer Guide states the two URL shapes plainly:

Configuration Tracking URL shape App can match it
Default, no attribute https://{domain}/CL0/{encodedUrl}/{index}/{messageId}/{hmac} No - path prefix is /CL0/ for every link in every campaign
ses:custom-path="myapp" https://{domain}/CL1/myapp/{encodedUrl}/{index}/{messageId}/{hmac} Yes - path prefix /CL1/myapp/ is stable and yours
Invalid value https://{domain}/CL0/{encodedUrl}/{index}/{messageId}/{hmac} No - and nothing in the API response says so

That third row is the one to plan around. The Developer Guide says the attribute "falls back to the default format if the value is invalid (same as omitting ses:custom-path)". A value of 33 characters, or one containing a slash or a plus sign, produces a perfectly valid tracked link that your verification file will never match. The send succeeds. CloudWatch records a click. The recipient lands in a browser.

The prerequisites are not trivial either. Per the Developer Guide, you need a custom redirect domain already configured (Part 1), a configuration set pointing at it through the TrackingOptions property (Part 2), and open or click event types selected in an event destination (Part 3). Only then does Part 4, the new deep linking section, apply. If you are still using the SES-operated awstrack.me domains, ses:custom-path does nothing for you, because you cannot host a verification file on a domain AWS owns.

The AASA example is the legacy format

Here is where the AWS documentation and Apple's documentation disagree.

The SES Developer Guide tells you to host this at https://{your-custom-redirect-domain}/.well-known/apple-app-site-association:


            {
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "{TEAMID}.{com.example.myapp}",
        "paths": ["/CL1/{myapp}/*"]
      }
    ]
  }
}
          

Apple's current "Supporting associated domains" documentation does not use appID and paths. It uses an appIDs array and a components array, where each component is a dictionary with / for path matching, # for fragment matching and ? for query parameter matching, plus an optional exclude flag. Apple's own example matches paths with entries like {"/": "/buy/*"}.

Both forms still work on current iOS. The paths array is the older syntax and Apple's documentation has moved on from it. The practical consequence is that a team following the AWS page lands on a format that does not match anything in Apple's guide, cannot express an exclusion, and cannot filter on a query parameter. If your redirect domain also serves web content you want to stay in the browser, the AWS example gives you no way to say so. Written against components, the same rule becomes {"/": "/CL1/myapp/*"} and sits beside whatever other rules that domain already needs.

The second thing the AWS page omits is timing. Apple states that its content delivery network requests the apple-app-site-association file for your domain within 24 hours, and that devices check for updates approximately once per week after app installation. Since macOS 11 and iOS 14, apps do not fetch the file from your web server at all; they fetch it from an Apple-managed CDN. So a ses:custom-path value you change on Monday is not a Monday change for installed users. Plan the path segment once and leave it alone.

Android does not read the path from the JSON file at all

The asymmetry between the two platforms is the part most likely to cost a sprint.

On iOS the path pattern lives in the server-hosted AASA file. On Android it does not. The SES Developer Guide is correct on this point and says so in a note: Android path-prefix matching is configured with an intent filter in AndroidManifest.xml using android:pathPrefix="/CL1/{myapp}/", not in assetlinks.json. The assetlinks.json file carries only the association - package_name, sha256_cert_fingerprints, and the delegate_permission/common.handle_all_urls relation.

Platform Where the path prefix lives Where the association lives Change requires
iOS Universal Links apple-app-site-association on the redirect domain Same file, appIDs Server edit, then up to 24h CDN fetch and roughly weekly device recheck
Android App Links (all versions) AndroidManifest.xml intent filter, android:pathPrefix assetlinks.json on the redirect domain App release and store rollout
Android 15+ dynamic rules assetlinks.json, dynamic_app_link_components assetlinks.json Server edit only, within manifest-declared scope

That last row is the escape hatch AWS does not mention. Android 15 (API level 35) and later, on devices with Google services installed, periodically retrieve assetlinks.json and merge a dynamic_app_link_components relation extension with the static manifest rules. It supports path, fragment and query matchers and an exclude flag, which is the closest Android equivalent to Apple's components. Two constraints matter: dynamic rules can only narrow the scope declared in the manifest, never widen it, and if any field in the file is malformed or empty, Android discards the dynamic rules entirely and falls back to the manifest. Devices on Android 14 (API level 34) and earlier ignore the relation extension fields completely.

There is also a hosting requirement that collides directly with how SES custom redirect domains are built. Android's documentation states that assetlinks.json must be served with content-type application/json, must be reachable over HTTPS, and "must be accessible without any redirects (no 301 or 302 redirects)". An SES custom redirect domain on HTTPS is, per the Developer Guide, a CDN such as Amazon CloudFront pointing at a regional SES tracking origin like r.us-east-1.awstrack.me, with the Host header forwarded. Your /.well-known/assetlinks.json and /.well-known/apple-app-site-association have to be served from that same hostname without a redirect, which means a CloudFront behaviour that serves those two paths from your own origin rather than forwarding them to SES. Apple applies the same rule: the file must be hosted "using https:// with a valid certificate and with no redirects".

Your analytics will not tell you which links were deep-linkable

The Developer Guide is explicit: "The ses:custom-path value does not appear in click event data. To identify which link was clicked in events, use ses:tags."

So the attribute that determines whether a click opens your app is invisible in the event stream that tells you the click happened. If you want to measure the rollout, you have to tag the same links twice - once with ses:custom-path for the operating system and once with ses:tags for yourself - and keep the two in sync by convention. Nothing enforces it.

The measurement window is fixed too. SES collects open and click metrics for 60 days after each email is sent, and the SES API has no method for retrieving them; you read them from CloudWatch, for example with aws cloudwatch get-metric-statistics --namespace AWS/SES --metric-name Click. Every open and click is counted at recipient level, and repeat clicks on the same link each count as a separate event.

One more caveat that predates this launch and still applies: SES states that event counts can be skewed by the recipient's email provider, including providers that cache images or links, in which case SES counts only the initial open. Deep link attribution built on click counts inherits that skew.

How to tell if this affects you

You are in scope if all of the following are true: you send transactional or marketing email through Amazon SES, you have click tracking enabled through a configuration set, you have a published iOS or Android app, and you expect links in those emails to open the app. If you disabled click tracking specifically to keep deep links working, this is the change that lets you turn it back on.

You are not in scope if you use the default SES-operated tracking domains, because the verification files have to live on a domain you control.

The work, in order:

  1. Confirm the custom redirect domain is on HTTPS and returns the expected x-amz-ses-region and x-amz-ses-request-protocol headers. The Developer Guide gives the check: curl --head https://{custom.domain.com}/favicon.ico.
  1. Pick one path segment and freeze it. 1-32 characters, case-sensitive, letters, digits, hyphens, periods and the _ character only.
  1. Serve both .well-known files from that hostname with no redirect and, for assetlinks.json, content-type application/json.
  1. Write the AASA against Apple's components format rather than the AWS example's paths array, unless you have a specific reason to stay on the legacy syntax.
  1. Ship the Android intent filter with android:pathPrefix="/CL1/{yourpath}/" in a release build. This is an app release, not a server change.
  1. Verify with adb shell pm verify-app-links --re-verify PACKAGE_NAME and then adb shell pm get-app-links PACKAGE_NAME, looking for a state of verified rather than none or legacy_failure.
  1. Add a matching ses:tags value so the click event stream can be reconciled against the deep link rollout.

Step 5 is the one that sets the schedule. On iOS the path pattern is a file edit. On Android it is a store release, and if you get the prefix wrong you ship another one. Decide the segment before anyone writes the AASA.

India-specific considerations

For teams sending from the Asia Pacific (Mumbai) Region, the redirect domain and its CDN origin have to sit in the same AWS Region as the SES identity - the Developer Guide requires the CNAME or CDN origin to point at the tracking domain for that Region, and SES recommends a separate subdomain per Region you send from. A single global tracking subdomain in front of multi-Region sending will not verify cleanly.

The verification files themselves are public by design and carry an Apple Team ID, a bundle identifier, a package name and a signing certificate fingerprint - no personal data - so they sit outside the scope of the Digital Personal Data Protection Act 2023. The click event stream is a different matter. It is recipient-level by construction, and if you are already applying consent controls to SES tracking, extending deep links does not change that obligation. Our note on the SES tracking override and bulk send consent limit covers where the per-recipient override actually applies.

Two adjacent constraints worth checking in the same sprint: the Android 17 targetSdk 37 adaptive layout migration, because an intent filter change means a release anyway and you may as well carry the API level with it, and ACM email validation ending in 2027, which touches the certificate on the same redirect domain.

What is still unknown

AWS has not published a way to read back which links in a sent message carried a valid ses:custom-path, so there is no server-side confirmation that the attribute was accepted rather than silently dropped. The only signal available today is behavioural: send a test, tap the link on a device with the app installed, and see whether the app opens.

Nor has AWS documented interaction with SES templates. The Developer Guide's warnings about template handling cover the {{ses:openTracker}} placeholder, where more than one instance returns a 400 BadRequestException; it says nothing about whether ses:custom-path survives template rendering intact. Test it in your template pipeline before assuming it does.

The real cost here is not the attribute. It is the release train.

FAQ

How eCorpIT can help

We build and ship iOS and Android applications, and this change lands squarely on the boundary between the email platform and the app release. If you need the verification files hosted correctly on a CloudFront-fronted SES redirect domain, the intent filter carried into a release build, and the adb verification checked before rollout, our custom mobile app development team does exactly that work. eCorpIT is CMMI Level 5, MSME Certified and ISO 27001:2022 certified. Tell us what you send and what your app expects at our contact page.

References

  1. Amazon SES click tracking now supports custom URL paths for mobile app deep linking, AWS What's New
  1. Configuring custom domains to handle open and click tracking, Amazon SES Developer Guide
  1. Amazon SES email sending metrics FAQs, Amazon SES Developer Guide
  1. Supporting associated domains, Apple Developer Documentation
  1. Configure website associations and dynamic rules, Android Developers
  1. Verify App Links, Android Developers
  1. Add Intent filters for App Links, Android Developers
  1. TrackingOptions, Amazon SES API v2 Reference
  1. CreateConfigurationSet, Amazon SES API v2 Reference
  1. Amazon SES tracking domains table, AWS General Reference
  1. Creating Amazon SES event destinations, Amazon SES Developer Guide
  1. Digital Asset Links v1 getting started, Google Developers

Last updated: 23 August 2026.

Frequently asked

Quick answers.

01 What does the ses:custom-path attribute do?
It adds a fixed path segment to Amazon SES click-tracking URLs. Without it, every tracked link uses the prefix /CL0/. With it, the link uses /CL1/ followed by your value, giving iOS Universal Links and Android App Links a stable path prefix they can match against a verification file you host.
02 When did Amazon SES release this?
AWS announced it on 14 August 2026 in the What's New feed, and it is available in all AWS Regions where Amazon SES is available. The configuration steps appear as Part 4 of the Developer Guide page on configuring custom domains to handle open and click tracking, after the three existing setup parts.
03 What happens if the value is invalid?
SES falls back to the default /CL0/ URL format, exactly as if the attribute had been omitted. There is no error and no signal in the API response. The permitted values are 1 to 32 characters, case-sensitive, using letters, digits, hyphens, periods and the _ character only. Anything outside that produces a link no app will match.
04 Do I need a custom redirect domain?
Yes. The verification files, apple-app-site-association and assetlinks.json, must be hosted on the click-tracking domain itself. That is impossible on the SES-operated tracking domains, so the custom redirect domain and its configuration set are prerequisites before Part 4 of the guide applies to you at all.
05 Why does the AWS AASA example look different from Apple's?
The AWS example uses Apple's older appID and paths syntax. Apple's current documentation uses an appIDs array with a components array that supports path, fragment and query matchers plus exclusions. Both forms work, but the legacy one cannot express exclusions or query filters on a shared domain.
06 Where does the path prefix go on Android?
In the app's AndroidManifest.xml intent filter, as android:pathPrefix, not in assetlinks.json. That file carries only the package name, certificate fingerprints and the relation. Changing the prefix on Android therefore means an app release, whereas on iOS it is a server-side file edit.
07 Can I change the path without shipping an app update?
On Android 15 and later, partly. Devices with Google services periodically fetch assetlinks.json and merge a dynamic_app_link_components relation extension with the manifest rules. Those dynamic rules can only narrow the manifest-declared scope, never widen it, and Android 14 and earlier ignore them entirely.
08 Will the custom path show up in my click events?
No. The Developer Guide states the value does not appear in click event data and directs you to ses:tags to identify which link was clicked. SES retains open and click metrics for 60 days and exposes them through CloudWatch rather than the SES API, so reconciling the two is a convention you maintain yourself.

About the author

Manu Shukla

Founder & Director

Founder of eCorpIT. Hands-on engineer leading senior-only delivery for AI apps, custom software, and cloud systems for global clients.

Subscribe

One engineering note a week. No fluff, no spam.

Senior-architect playbooks on AI agents, mobile apps, cloud, security, data, and marketing — delivered every Wednesday.

Past the reading

Read enough. Let's build something.

A senior architect responds in 24 working hours with scope, indicative cost, and a timeline. NDA before any technical conversation.