2

I'm trying to put some content in my automated reply messages from Google Apps Script. My project has a AutomatedResponseTemplate.html the script hits for some response HTML string to send. That file is defined like this :

<!DOCTYPE html>
<html>
    <head>
        <script src=https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js></script>
        <script src=https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.1/mustache.js></script>
        <script>
            $(function() { 
                let data = <?= JSON.stringify(messageData) ?>
                // make request to "server"
                template = $('body').html()
                rendering= Mustache.render(template, data)
                $('body').html(template)
            })
        </script>
        <style>
            #closing { 
                white-space: pre-line;
            }

            .separate-lines { 
                white-space: pre-line;
            }

            .first { 
                width: 80px;
            }

            .left {
                float: left;
            }
        </style>
    </head>
    <body>

        <p>
            {{name}}
        </p>
        <p>
        Thank you for reaching out to us! This is an automated reply, and one of us shall reach out to you, 
                    for real, shortly. Here is a copy of the message you sent us for reference:
        </p>
        <p>
        <blockquote class=separate-lines>
        <span><label class="first left">Sender:</label> {{sender}}</span>
        <span><label class="first left">Subject:</label> {{subject}}</span>
        <span><label class="first left">Message:</label> {{message}}</span>
        </blockquote>
        
        </p>
                    
                    
        <p id=closing>           
                    Mike Warren
                    Open Source Roads
        </p>
    </body>
</html>

To separate concerns, and keep things RESTful, I have the script send the relevant data to the HTML via that tag. There's a working pure-client-side version prior and I got the idea to do it that way from thinking about it and the implementation here.

There's one problem: it doesn't work. Even if I append some non-template code

$('#data').text('This was inserted by jQuery')

and a tag

<p id=data></p>

...nothing changes.

What in the world is going on?

UPDATE I updated the <script> tag to this:

<script>
        $(function() { 
            let data = <?!= JSON.stringify(messageData.data) ?>
            // make request to "server"
            template = $('body').html()
            rendering= Mustache.render(template, data)
            $('body').html(rendering)
            $('#data').text('This text was inserted by jQuery')
        })
    </script>

, enclosed the src values on the client-side dependencies with quotes (idk why that matters to Google Apps Script, as it works fine elsewhere), and provided a doGet for debugging purposes:

function doGet(e) { 
  
  var messageData = { 
    data: {
      sender:  'mwarren04011990@gmail.com',
      name: 'Test User',
      recipient: Session.getActiveUser().getEmail(),
      subject: 'Test email',
      message: 'Hello world'
    }
  }
  var template =  HtmlService
    .createTemplateFromFile('AutomatedResponseTemplate')
  template.messageData = messageData
  return template
    .evaluate()
    .setSandboxMode(HtmlService.SandboxMode.IFRAME)
}

Also, the function that is supposed to get this client side template rendering as a string has this code:

/**
 * Generates an email message body in response to the sender's `messageData`
 * @param {object} messageData - a JSON object with at least the following: 
 *  - `sender`
 *  - `name` 
 *  - `subject`
 *  - `message`
 */
function getAutomatedResponseTo(messageData) { 
  messageData = messageData || {};
  if (!messageData.sender) return '';
  if (!messageData.name) return '';
  if (!messageData.subject) return '';
  if (!messageData.message) return '';
  

  var template = HtmlService
    .createTemplateFromFile('AutomatedResponseTemplate')
  template.messageData = messageData;
  
  return template
    .evaluate()
    .setSandboxMode(HtmlService.SandboxMode.IFRAME)
    .getContent()
}

Is my trying to separate the concerns this way infeasible?

Rubén
  • 34,714
  • 9
  • 70
  • 166
Mike Warren
  • 3,796
  • 5
  • 47
  • 99

3 Answers3

2

I have replicated your error. If you look at the developer tools in chrome you will see the following error:

jquery not found

This means that jQuery is not available.

If you look at the network tab in developer tools you will see that the attempt to load jquery has failed and the url is badly mangled:

script load error

The solution is to put quotes around the resources you are loading using the script tag:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.1/mustache.js"></script>

When that is done the dialog seems to work fine and the Mustache templates are populated correctly. Some browsers can live without the quotes but it seems that Google Apps Script cannot.

Rubén
  • 34,714
  • 9
  • 70
  • 166
Aidan
  • 1,550
  • 1
  • 13
  • 20
1

I think you are missing an !. This is the code that I use:

<script>
    var data = <?!= JSON.stringify(dataFromServerTemplate) ?>;
</script>

you can do a console.log(data) and look at it in developer tools to see what you get.

Rubén
  • 34,714
  • 9
  • 70
  • 166
Aidan
  • 1,550
  • 1
  • 13
  • 20
  • That is a step in the right direction, and now, after some more changes (I forgot to use `rendering`, also I forgot to send the `data` member object, and I added a doGet with template rendering), I am able to GET the page just fine, but in the string output, it doesn't output correctly (the Mustaches are still there). I'll update the question to reflect these changes. – Mike Warren Aug 09 '18 at 17:03
0

I just went ahead and made Google Apps Script take care of all the templating. (Sorry, Mustache.js, but you didn't seem to be working without a browser open to show your work!)

I took out the <script> tags, and replaced the mustaches with the Google Script template tags containing the data fields directly. For example, I replaced {{name}} with <?= messageData.name ?>.

Mike Warren
  • 3,796
  • 5
  • 47
  • 99
  • I also replaced all those `return ''` with error-throwing statements, to remedy the issue of a blank email being sent on invalid data. – Mike Warren Aug 09 '18 at 18:09