HelloKoding

Practical coding guides

Contact Form Example with Spring Boot, FreeMarker and Amazon SES

This tutorial will walk you through the steps of creating a Contact Form Example with Spring Boot, FreeMarker and Amazon SES.

What you’ll build

Spring Boot Form Concat

What you’ll need

Stack

  • Java, Java Mail API
  • Spring Boot
  • FreeMarker
  • HTML, CSS

Init project structure and dependencies

Project structure

├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── hellokoding
│       │           └── form
│       │               ├── model
│       │               │   ├── MailProperties.java
│       │               │   └── User.java
│       │               ├── service
│       │               │   ├── SESService.java
│       │               │   └── SendingMailService.java
│       │               ├── web
│       │               │   └── FormController.java
│       │               └── WebApplication.java
│       └── resources
│           ├── static
│           │   ├── css
│           │   │   └── main.css
│           │   └── js
│           │       └── main.js
│           ├── templates
│           │   └── form.ftl
│           └── application.properties
└── pom.xml

Project dependencies

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.hellokoding.springboot</groupId>
    <artifactId>freemarker.form.contact</artifactId>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Define DTO, Service, Controller and View Template

Data transfer object

User.java

package com.hellokoding.form.model;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;

public class User {
    @NotEmpty
    private String name;

    @NotEmpty
    private String message;

    @NotEmpty
    @Email
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Service

SendingMailService.java

package com.hellokoding.form.service;

public interface SendingMailService {
    boolean sendMail(String subject, String body);
}

SESService.java

package com.hellokoding.form.service;

import com.hellokoding.form.model.MailProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

@Service
public class SESService implements SendingMailService {
    private final MailProperties mailProperties;

    @Autowired
    SESService(MailProperties mailProperties){
        this.mailProperties = mailProperties;
    }

    public boolean sendMail(String subject, String body) {
        try {
            Properties props = System.getProperties();
            props.put("mail.transport.protocol", "smtp");
            props.put("mail.smtp.port", mailProperties.getSmtp().getPort());
            props.put("mail.smtp.starttls.enable", "true");
            props.put("mail.smtp.auth", "true");

            Session session = Session.getDefaultInstance(props);

            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(mailProperties.getFrom(), mailProperties.getFromName()));
            msg.setRecipient(Message.RecipientType.TO, new InternetAddress(mailProperties.getTo()));
            msg.setSubject(subject);
            msg.setContent(body, "text/html");

            Transport transport = session.getTransport();
            transport.connect(mailProperties.getSmtp().getHost(), mailProperties.getSmtp().getUsername(), mailProperties.getSmtp().getPassword());
            transport.sendMessage(msg, msg.getAllRecipients());
            return true;
        } catch (Exception ex) {
            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, ex.getMessage(), ex);
        }

        return false;
    }
}

Controller

FormController.java

package com.hellokoding.form.web;

import com.hellokoding.form.model.User;
import com.hellokoding.form.service.SendingMailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import javax.validation.Valid;

@Controller
public class FormController {
    @Autowired
    SendingMailService sendingMailService;

    @GetMapping("/")
    public String index() {
        return "redirect:/form";
    }

    @GetMapping("/form")
    public String formGet(Model model) {
        model.addAttribute("user", new User());
        return "form";
    }

    @PostMapping("/form")
    public String formPost(@Valid User user, BindingResult bindingResult, Model model) {
        if (bindingResult.hasErrors()) {
            return "form";
        }

        model.addAttribute("noErrors", true);
        model.addAttribute("user", user);
        String subject = user.getName() + " " + user.getEmail() + " sent you a message";
        sendingMailService.sendMail(subject, user.getMessage());
        return "form";
    }
}

View template

form.ftl

<#import "/spring.ftl" as spring />

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Contact Form Example</title>
        <link href="/css/main.css" rel="stylesheet">
    </head>
    <body>
        <h2>Contact Form Example</h2>

        <@spring.bind "user"/>
        <#if user?? && noErrors??>
            Your data has been sent<br>
            Name: ${user.name}<br>
            Email: ${user.email}<br>
            Message: ${user.message}<br>
        <#else>
            <form action="/form" method="post">
                Name:<br>
                <@spring.formInput "user.name"/>
                <@spring.showErrors "<br>"/>
                <br><br>
                Email:<br>
                <@spring.formInput "user.email"/>
                <@spring.showErrors "<br>"/>
                <br><br>
                Message:<br>
                <@spring.formTextarea "user.message"/>
                <@spring.showErrors "<br>"/>
                <br><br>
                <input type="submit" value="Submit">
            </form>
        </#if>

        <script src="/js/main.js"></script>
    </body>
</html>

Config and Run

Application Configuration

WebApplication.java

package com.hellokoding.form;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(WebApplication.class, args);
    }
}

application.properties

spring.freemarker.template-loader-path: classpath:/templates
spring.freemarker.suffix: .ftl

mail.smtp.host={YOUR_SES_SMTP_HOST}
mail.smtp.port={YOUR_SES_SMTP_PORT}
mail.smtp.username={YOUR_SES_SMTP_USERNAME}
mail.smtp.password={YOUR_SES_SMTP_PASSWORD}
mail.from={YOUR_FROM_EMAIL}
mail.from-name={YOUR_FROM_NAME}
mail.to={YOUR_TO_EMAIL}

Make sure updating all macros such as {YOUR_SES_SMTP_HOST} and {YOUR_SES_SMTP_PORT} to your configs

MailProperties.java

package com.hellokoding.form.model;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {
    public static class SMTP {
        String host;
        String port;
        String username;
        String password;

        public String getHost() {
            return host;
        }

        public void setHost(String host) {
            this.host = host;
        }

        public String getPort() {
            return port;
        }

        public void setPort(String port) {
            this.port = port;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    private SMTP smtp;
    private String from;
    private String fromName;
    private String to;

    public SMTP getSmtp() {
        return smtp;
    }

    public void setSmtp(SMTP smtp) {
        this.smtp = smtp;
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getFromName() {
        return fromName;
    }

    public void setFromName(String fromName) {
        this.fromName = fromName;
    }
}

Run the application

Type the following Maven command on the terminal console at the project root directory

mvn clean spring-boot:run

Source code

https://github.com/hellokoding/hellokoding-courses/tree/master/springboot-examples/springboot-freemarker-form-contact

Follow HelloKoding