Nicklas Wiegandt

About this blog

My first post on my new blog. This posts is about the blog itself and how it’s made.

I created this blog to write about DevOp’s things that keep me occupied. These will mainly be solutions to problems for which I had to search and try around for a long time. With this I want to achieve that others do not have to search so long for the right solution. Maybe, if I find time and motivation, I will also write articles about my work on MediathekView. And maybe I will also write articles about frameworks & technologies I am currently busy oneself with. And maybe I write articles about frameworks and technologies I’m currently working with.

The blog itself is made with Jekyll and AsciiDoc. It’s hosted on GitHub where you can also find the source: https://github.com/nicklas2751/nicklas2751.github.io Because this don’t allows to send E-Mails on server side, I created a AWS Lambda for the contact form.

This is the source of my contact form lambda:

lambda_function.py view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from __future__ import print_function
from botocore.exceptions import ClientError
from urllib.request import urlopen
import boto3
import json
import requests

def lambda_handler(event, context):
    if "g-recaptcha-response" in event and "mail" in event and "text" in event:
        success = checkRecaptcha(event["g-recaptcha-response"])
    else:
        success = False

    if success:
        send_email(event["mail"],event["text"])
    else:
        print("RECaptcha failed!")

    return {
        "location": event["referer"]
    }

def checkRecaptcha(captchaCode):
    requestData = { "secret": "mySecret", "response": captchaCode }
    data = requests.post("https://www.google.com/recaptcha/api/siteverify", data=requestData)
    result = data.json()
    return result.get('success', None)

def send_email(userMail, content):
    # Replace sender@example.com with your "From" address.
    # This address must be verified with Amazon SES.
    SENDER = "My Sender <cloud@my.domain>"

    # Replace recipient@example.com with a "To" address. If your account
    # is still in the sandbox, this address must be verified.
    RECIPIENT = "recipient@my.domain"

    # If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
    AWS_REGION = "eu-west-1"

    # The subject line for the email.
    SUBJECT = "A user has sent you a message"

    # The character encoding for the email.
    CHARSET = "UTF-8"

    # Create a new SES resource and specify a region.
    client = boto3.client('ses',region_name=AWS_REGION)

    # Try to send the email.
    try:
        #Provide the contents of the email.
        response = client.send_email(
            Destination={
                'ToAddresses': [
                    RECIPIENT
                ]
            },
            ReplyToAddresses=[
                userMail,
            ],
            Message={
                'Body': {
                    'Text': {
                        'Charset': CHARSET,
                        'Data': content,
                    },
                },
                'Subject': {
                    'Charset': CHARSET,
                    'Data': SUBJECT,
                },
            },
            Source=SENDER,
        )
    # Display an error if something goes wrong.
    except ClientError as e:
        print(e.response['Error']['Message'])
    else:
        print("Email sent! Message ID:"),
        print(response['MessageId'])

Because the HTML form sends it’s data as www-form-urlencoded the following API gateway integration request mapping template is needed:

api_gateway_mapping_template.vtl view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
## convert HTML POST data or HTTP GET query string to JSON

## get the raw post data from the AWS built-in variable and give it a nicer name
#if ($context.httpMethod == "POST")
 #set($rawAPIData = $input.path("$"))
#elseif ($context.httpMethod == "GET")
 #set($rawAPIData = $input.params().querystring)
 #set($rawAPIData = $rawAPIData.toString())
 #set($rawAPIDataLength = $rawAPIData.length() - 1)
 #set($rawAPIData = $rawAPIData.substring(1, $rawAPIDataLength))
 #set($rawAPIData = $rawAPIData.replace(", ", "&"))
#else
 #set($rawAPIData = "")
#end

## first we get the number of "&" in the string, this tells us if there is more than one key value pair
#set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())

## if there are no "&" at all then we have only one key value pair.
## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
## the "empty" kv pair to the right of the ampersand will be ignored anyway.
#if ($countAmpersands == 0)
 #set($rawPostData = $rawAPIData + "&")
#end

## now we tokenise using the ampersand(s)
#set($tokenisedAmpersand = $rawAPIData.split("&"))

## we set up a variable to hold the valid key value pairs
#set($tokenisedEquals = [])

## now we set up a loop to find the valid key value pairs, which must contain only one "="
#foreach( $kvPair in $tokenisedAmpersand )
 #set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
 #if ($countEquals == 1)
  #set($kvTokenised = $kvPair.split("="))
  #if ($kvTokenised[0].length() > 0)
   ## we found a valid key value pair. add it to the list.
   #set($devNull = $tokenisedEquals.add($kvPair))
  #end
 #end
#end

## next we set up our loop inside the output structure "{" and "}"
{
  "referer" : "$input.params('referer')",
#foreach( $kvPair in $tokenisedEquals )
  ## finally we output the JSON for this pair and append a comma if this isn't the last pair
  #set($kvTokenised = $kvPair.split("="))
 "$util.urlDecode($kvTokenised[0])" : #if($kvTokenised[1].length() > 0)"$util.urlDecode($kvTokenised[1])"#{else}""#end#if( $foreach.hasNext ),#end
#end
}