0

I am new to AWS Lambda and I am trying to send an email with details submitted in an HTML form using AWS SES. I tested out the lambda function with hard coded values and the emails worked fine. Below is the initial code:

# Lambda Function for Contact Forms using AWS SES

import boto3
import datetime

def lambda_handler(event, context):
    client = boto3.client('ses')

    response = client.send_email(
        Destination={
            'BccAddresses': [
            ],
            'CcAddresses': [
                '[email protected]',
            ],
            'ToAddresses': [
                '[email protected]',
            ],
        },
        Message={
            'Body': {
                'Html': {
                    'Charset': 'UTF-8',
                    'Data': 'This message body contains HTML formatting. It can, for example, contain links like this one: <a class="ulink" href="http://docs.aws.amazon.com/ses/latest/DeveloperGuide" target="_blank">Amazon SES Developer Guide</a>.',
                },
                'Text': {
                    'Charset': 'UTF-8',
                    'Data': 'This is the message body in text format.',
                },
            },
            'Subject': {
                'Charset': 'UTF-8',
                'Data': 'Test email sent at '+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            },
        },
        ReplyToAddresses=['[email protected]',
        ],
        Source='[email protected]',
    )

I am now trying to replace the form data (post method) in the email body. This is my new code:

# Lambda Function for Contact Forms using AWS SES

import boto3
import datetime

def lambda_handler(event, context):
    client = boto3.client('ses')
    error = None

    # Read form values.
    full_name = event.get('fullname')
    email_addr = event.get('emailid')
    subject = event.get('subject')
    msg_body = event.get('msgbody')
    
    # Check form data.
    if not full_name:
        error = 'Full name is required.'
    elif not email_addr:
        error = 'Email address is required.'
    elif not subject:
        error = 'Subject is required.'
    elif not msg_body:
        error = 'Message body is required.'

    if error is None:
        response = client.send_email(
            Destination={
                'BccAddresses': [
                ],
                'CcAddresses': [
                    '[email protected]',
                ],
                'ToAddresses': [
                    '[email protected]',
                ],
            },
            Message={
                'Body': {
                    'Html': {
                        'Charset': 'UTF-8',
                        'Data': msg_body,
                    },
                    'Text': {
                        'Charset': 'UTF-8',
                        'Data': msg_body,
                    },
                },
                'Subject': {
                    'Charset': 'UTF-8',
                    'Data': subject+' | example.com | '+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                },
            },
            ReplyToAddresses=[email_addr,
            ],
            Source='[email protected]',
        )

The above code does not throw any error in the Cloud Watch logs but it does not deliver the email also. What am I missing here?

Following is the cloud watch log:

START RequestId: 9ce6de23-9f1d-4d67-a686-ea043692221e Version: $LATEST
END RequestId: 9ce6de23-9f1d-4d67-a686-ea043692221e
REPORT RequestId: 9ce6de23-9f1d-4d67-a686-ea043692221e  Duration: 25.39 ms  Billed Duration: 26 ms  Memory Size: 128 MB Max Memory Used: 65 MB  

The HTML form code is shared below:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Contact | Example Website</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Example Description">
    <meta name="keywords" content="example,contact,form">
    <meta name="author" content="example.com">
    <script src="js/jquery-3.4.1.min.js"></script>
    <link rel="stylesheet" href="css/bootstrap.min.css"></link>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/formcheck.js"></script>
    <link rel="icon" href=""></link>
    <link href="css2/sticky-footer-navbar.css" rel="stylesheet"></link>
    <link rel="icon" href="assets/example-logo-small.png" type="image/png" sizes="16x16"></link>
    <!-- Google ReCaptcha v2 -->
    <script src="https://www.google.com/recaptcha/api.js"></script>
  </head>
  <body>
   <header>
    <!-- Fixed navbar -->
      <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
        <a class="navbar-brand" href="index.html">
         <img src="assets/example-logo-small.png" alt="Logo" style="width:50px;">
        </a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarCollapse">
          <ul class="navbar-nav mr-auto">
            <li class="nav-item">
              <a class="nav-link" href="index.html">Home</a>
            </li>
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" href="#" id="navbardrop1" data-toggle="dropdown">Products</a>
              <div class="dropdown-menu">
               <a class="dropdown-item" href="1.html">1</a>
               <a class="dropdown-item" href="2.html">2</a>
               <a class="dropdown-item" href="3.html">3</a>
               <a class="dropdown-item" href="4.html">4</a>
               <a class="dropdown-item" href="5.html">5</a>
               <a class="dropdown-item" href="6.html">6</a>
              </div>
            </li>
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" href="#" id="navbardrop2" data-toggle="dropdown">Details</a>
              <div class="dropdown-menu">
               <a class="dropdown-item" href="7.html">7</a>
               <a class="dropdown-item" href="8.html">8</a>
               <a class="dropdown-item" href="9.html">9</a>
               <a class="dropdown-item" href="10.html">10</a>
              </div>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="list.html">List</a>
            </li>
            <li class="nav-item active">
              <a class="nav-link" href="contact.html">Contact<span class="sr-only">(current)</span></a>
            </li>
          </ul>
        </div>
      </nav>
   </header>
   <!-- Begin page content -->
   <main role="main" class="container">
    <div class="container mt-5" style="width:75%">
     <form action="https://mylambdafunction.lambda-url.us-east-1.on.aws/"  method="post" class="needs-validation" novalidate>
      <div class="form-group">
       <label for="fullname">Full Name:</label>
       <input type="text" class="form-control" id="fullname" placeholder="Enter full name" name="fullname" required>
       <div class="valid-feedback">Valid.</div>
       <div class="invalid-feedback">Please fill out this field.</div>
      </div>
      <div class="form-group">
       <label for="emailid">Email Address:</label>
       <input type="email" class="form-control" id="emailid" placeholder="Enter email address" name="emailid" required>
       <div class="valid-feedback">Valid.</div>
       <div class="invalid-feedback">Please fill out this field in correct format.</div>
      </div>
      <div class="form-group">
       <label for="subject">Subject:</label>
       <input type="text" class="form-control" id="subject" placeholder="Enter subject" name="subject" required>
       <div class="valid-feedback">Valid.</div>
       <div class="invalid-feedback">Please fill out this field.</div>
      </div>
      <div class="form-group">
       <label for="msgbody">Message:</label>
       <textarea class="form-control" rows="5" id="msgbody" placeholder="Enter message" name="msgbody" required></textarea>
       <div class="valid-feedback">Valid.</div>
       <div class="invalid-feedback">Please fill out this field.</div>
      </div>
      <div class="form-group form-check">
       <label class="form-check-label">
       <input class="form-check-input" type="checkbox" name="checkdata" required> I agree to the <a href="declaration.html" target="_blank">declaration</a>.
       <div class="valid-feedback">Valid.</div>
       <div class="invalid-feedback">Please select the checkbox to continue.</div>
       </label>
      </div>
      <button type="submit" class="btn btn-dark mb-2">Send</button>
      <div class="g-recaptcha" data-sitekey="my-site-key"></div>
     </form>
    </div>
   </main>
   <!-- Footer Navbar -->
   <div class="container">
    <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-bottom justify-content-center">
     <span class="navbar-text text-white">Copyright &copy Example</span>
    </nav>
   </div>
  </body>
</html>

1 Answer 1

2

I can't diagnose in it's entirety, but I've re-written the snippet in a way the allows me to debug my Lambda's with a little more feedback. Keep in a mind, a lambda succeeding doesn't necessarily mean the code was executed as you expect it to, which is where feedback from the invocation helps validate expected behavior.

If the final response provides a MessageId and a code of 200, I would explore the email client settings next.

import boto3
import datetime, json

def lambda_handler(event, context):
    client = boto3.client('ses')

    full_name = event.get('fullname')
    email_addr = event.get('emailid')
    subject = event.get('subject')
    msg_body = event.get('msgbody')

    if None in [full_name, email_addr, subject, msg_body]:
        return {
            "statusCode": 500,
            "body": json.dumps("Error in email variable definitions.")
        }
    

    try:
        response = client.send_email(...)
    except Exception as e:
        return {
            "statusCode": 500,
            "body": json.dumps("Failed to send email: {}".format(e))
        }

    return {
        "statusCode": 200,
        "body": "Email ID: {} sent from Lambda.".format(response.get("MessageId"))
    }
    
Sign up to request clarification or add additional context in comments.

6 Comments

Hi Michael, thanks for your code snippet. I tested the above and I get the following error: "Error in email variable definitions." - this probably means that the form is passing null values or the lambda event handler is unable to retrieve the appropriate values from the event variable. Do you have any suggestion? Is this the right syntax? full_name = event.get('fullname')
Update: If I use full_name = event['fullname'] to retrieve the values, I get the following error - Internal Server Error. If I debug the CloudWatch logs for this event it shows me a key error - [ERROR] KeyError: 'fullname'. Any suggestion?
Update: If I use the following code, I get a different error: event_obj = event['body'] full_name = event_obj['fullname'] email_addr = event_obj['emailid'] subject = event_obj['subject'] msg_body = event_obj['msgbody'] Now, the error is "string indices must be integers".
Based on your comments my guess (without seeing how you are invoking the lambda) is that you are not defining your variables (correctly or not at all) at invocation time. If you are invoking your function with a manual test even, do you have key value pairs defined in your Event JSON?
I am invoking my lambda function through an HTML form with a POST operation defined on the submit button. I have used the new lambda url feature released by AWS. So it is integrated with API Gateway. The lambda url is directly placed in the action tag of the contact form. I have updated my original question to include the HTML code. Can you kindly review and advise?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.