Score:0

AWS (SES + API Gateway) + HTML Form fails. Error is: InvalidParameterValue: Missing final '@domain'

kg flag

I'm trying to set up a contact form on my site, I feel I am close but there is something funky going on with the source address value. I'm passing the data as URL encoded instead of multipart as I only need some text.

Contact form:

<form id='contact-form'>
  <label for='replyTo'>Email</label>
  <input name='replyTo' id='replyTo' type='email' autocomplete='email' required>
  <label for='subject'>Subject</label>
  <input name='subject' id='subject' required>
  <label for='message'>Message</label>
  <textarea name='message' id='message' autocapitalize='sentences' maxlength='3000' minlength='10' placeholder='Comment text' rows='3' spellcheck='true' required></textarea>
  <button id='submit-btn' type='button'>Send</button>
</form>

Javascript handler:

const submitBtn = document.getElementById('submit-btn'),
      htmlForm = document.getElementById('contact-form'), //contact form
      endpoint = "https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/Email";

submitBtn.addEventListener('click', () => {
  const formData = new FormData(htmlForm),
  urlEncodedData = new URLSearchParams();
  for (const pair of formData.entries()) {
    urlEncodedData.append(pair[0], pair[1]);
  }
  htmlForm.requestSubmit();
  fetch(endpoint, {
    method: "post",
    body: urlEncodedData,
    headers: {
      "Content-Type": "application/x-www-form-urlencoded"
    }
  }).then(response => {
    if (response.ok) {
      resetForm();
    } else {
      throw new Error('HTTP error. Status: ${response.status}');
    }
  });
});

htmlForm.addEventListener('submit', (event) => {
  event.preventDefault(); // prevents submitting to self (page)
});

Lambda function:

const AWS = require('aws-sdk'),
      ses = new AWS.SES(),
      querystring = require('querystring');

exports.handler = async (event) => {
  const formData = querystring.parse(event.body),
        message = formData.message,
        replyTo = formData.replyTo,
        subject = formData.subject,
  emailParams = {
    Source: "form@<verified_domain_tld_here>",
    Destination: {
      ToAddresses: ["<my actual email address>"]
    },
    Message: {
      Subject: {
        Data: `${subject}`
      },
      Body: {
        Text: {
          Data: `${message}`
        }
      }
    },
    ReplyToAddresses: [`${replyTo}`]
  };
  try {
    await ses.sendEmail(emailParams).promise();
    console.log(successMessage);
    return {
      statusCode: 200,
      body: JSON.stringify({ message: successMessage })
    };
  } catch (err) {
    console.log(err);
    return {
      statusCode: err.statusCode || 500,
      body: JSON.stringify({ message: err.message || errorMessage })
    };
  }
};
Falken avatar
kg flag
I altered the code a bit to return the response body, and it is base64 encoded. This might be preventing the Lambda function from parsing it!
Score:0
kg flag

Turns out the data was being encoded into Base64 by this: const formData = new FormData(htmlForm) which means I had to decode it on the server side before the body could be properly parsed.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.