Send a custom container enrollment link via email

Hi

This is possible, and not too difficult. In short, every JourneyApps container registers a custom URL handler once it is installed on the device. This custom URL handler allows you to use “deep linking” to enroll into the container using a link with a very specific format, amongst other things.

The problem you will face with just trying to email a link in that special format is that most modern email clients actively remove links that use custom URL handler patterns, even when you try to include it in the HTML body of the email. This means that in order to actually do this you will need a 2 step process.

  1. Send email with link to a webpage
  2. Have that webpage redirect using the special custom URL handler

And luckily you can do both fairly easily within CloudCode. Like so

CC task to generate enrollment link and email

const sgMail = require("@sendgrid/mail");
const handlebars = require("handlebars");
// To send email, a SendGrid API key is required
sgMail.setApiKey(""); 

const emailTemplate = handlebars.compile(`
<!DOCTYPE html>
<html>
  <body>
    <h1>Welcome to your app</h1>
    <p>Please follow the link below to enrol in your new app</p>

    <a href="{{ webtaskLink }}">Enroll Here</a>	
  </body>
</html>
`);

export async function run(params) {
    // Generate an HTML email, using handlebars again
    var userID;
    if (params) {
        userID = params.userID
    } else {
        userID = "some user ID"
    }

    var options = {
        method: "POST",
        headers: {
            "Authorization": `Bearer ${this.backend.token}`
        }
    }

    // Get a new enrollment token / url for the userID in question from the Backend Users API: https://docs.journeyapps.com/reference/backend-api/api-reference/manage-app-users-and-sessions
    var response = await fetch(`${this.backend.url}/users/${userID}/authentication-token`, options)

    if (!response.ok) {
        console.log("Error, response not ok");
        var message = await response.text();
        console.log(`Error: ${message}`);
        return;
    } else {
        var body = await response.json();
        var url = body.url;
        
        // custom URL scheme of the container in question
        // reach out to JourneyApps support for the custom URL scheme of your containers if you are not sure what they are
        var urlScheme = "journeyapps:///"; // JourneyApps vanilla container custom URL scheme

        // replace the default enrollment url prefix with the custom URL scheme
        var customEnrollmentLink = url.replace('https://embark.mobi/', urlScheme)
        
        // URL encode the new enrollment link
        var encodedURL = encodeURIComponent(customEnrollmentLink);

        // create the full link that will be included in the HTML email body
        // it's a link to a different CC webtask, hosted at the specific domain that you specify per backend
        // and that will be expecting the custom enrollment url as a URL parameter
        
        const backendDomain = "" // Insert your full backend domain here, including https:// (Backend domains are specified on a per deployment basis using the Deployment Settings interface
        // Example
        // const backendDomain = "https://exampleDomainName.poweredbyjourney.com"

        const webTaskName = "" // Insert the name of your CC webtask here
        var taskUrl = `${backendDomain}/${webTaskName}?url=${encodedURL}`
        
        const html = emailTemplate({ webtaskLink: taskUrl });

        console.log("HTML Template: ", html);
        const email = {
            from: "", // from email address
            to: "", // to email address
            subject: "", // email subject
            html: html, // Or: text: "Plain email"
        };
        try {
            await sgMail.send(email);
        } catch (error) {
            // This helps for debugging
            if (error.response) {
                console.error(error.response.body);
            }
            throw error;
        }

    }
}

You can obviously decide how you want to trigger this task, but in short it just generates a new enrollment link for a specific user, creates the custom enrollment URL from that link, and then sends an email with a link to the redirect webpage, passing the custom url as a parameter to that page

CC Webtask to serve a redirect webpage
The name of this task needs to match the value of webTaskName in the previous block of code

const handlebars = require('handlebars')

// HTML template that will be used as the webpage
// Includes an immediate redirect to the specified 'redirectURL' 
const webpageTemplate = handlebars.compile(`
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="refresh" content="0; url='{{ redirectURL }}'" />
  </head>
  <body>
    <p>Please follow <a href="{{ redirectURL }}">this link</a>.</p>
  </body>
</html>
`)

// This must be defined, and should return either access.authorized() or access.unauthorized()
export async function authenticate({request, access}) {
    return access.authorized();
}

// HTTP GET request
export async function get({params, request, response, authContext}) {
    // create the HTML - passing in the custom URL that was included as a URL param
    const html = webpageTemplate({ redirectURL: params.url });
    
    // render the HTML page
    response.contentType('text/html');
    return html;
    
}

export async function run() {
    // This function is not used for web tasks, but can be used for editor testing
}

So basically the email recipient will get the email with the link to the webtask, they will click on the link which will take them to the webtask, the webtask will serve the HTML page and immediately redirect to the redirect URL that was passed along as a URL parameter. At this point, if the custom container is installed on the user’s device, the user would get enrolled into the custom container.

I hope this helps