There are two ways to create an HTML email form
- Use the
mailto: address
action element. - Use backend script to handle data and send emails.
The first method is something you shouldn’t try. Sending form data directly to an email from a web form without server-side processing isn’t recommended due to security and privacy risks.
The following tutorial covers methods that include server-side scripting. And I added a special section to ensure that any sensitive information is encrypted and transmitted securely.
First, I cover the front end that sends an HTTP POST request to the backend. Next, I go into the backend to send emails, using Laravel, Java, Node.js, Python, or C#. Then, I’ll give you tips and some examples of security measures.
How to create an HTML contact form – Quick guide
As said, I’ll be covering the backend scripting for a few popular languages and frameworks. So, to make the HTML code easily integrated with the scripts, it’s critical to ensure the HTML form is universally compatible with each language.
Here’s how to create a simple HTML form:
- Form structure
Start with a basic HTML form structure. The action
attribute should be set to a generic handler, which can be specified in the backend script.
<form action="process-form" method="post" enctype="multipart/form-data">
<!-- Form elements will go here -->
</form>
Note: The enctype="multipart/form-data"
is important if you plan to include file uploads. It’s compatible with all backend technologies. The backend scripts also feature exemplary snippets without the support for file uploads.
- Input elements
As needed, you can include the following elements.
Text fields
<label for="name">Name:</label>
<input type="text" id="name" name="name">
Message field
<label for="message">Message:</label>
<textarea id="message" name="message" rows="4" cols="50">
</textarea>
Message field notes:
<label for="message">
: This label is associated with thetextarea
. Thefor
attribute should match theid
of thetextarea
, which helps with accessibility.<textarea>
: This is the element used for multi-line text input.id="message"
: The ID of the textarea, which is referenced by the label.name="message"
: Thetextarea
name attribute is important as it’s the key that will be used to access this piece of data on the server side.rows="4"
andcols="50"
: These attributes define the size of thetextarea
.rows
specifies the number of lines, andcols
specifies the width in terms of character columns. You can adjust these numbers based on your layout requirements.
Email field
<label for="email">Email:</label>
<input type="email" id="email" name="email">
Submit button
<input type="submit" value="Submit">
- Form action
The action
attribute in the form should be a placeholder that will be replaced by the specific endpoint of your backend technology (Laravel, Java, Node.js, Python, or C#).
For instance, in Laravel, you might set it to a route defined in your web routes, while in Node.js, it might point to an Express.js route.
- Backend integration (quick notes)
- Laravel: Use a route in
web.php
to handle the form submission. - Java: Set up a servlet or a Spring Controller to process the form.
- Node.js: Use an Express.js route to handle the POST request.
- Python (Flask/Django): Define a view function or a Django view to process the form.
- C# (ASP.NET): Use a controller action in an ASP.NET MVC application.
- Processing form data
Each backend technology will have its way of accessing form data (e.g., request.getParameter()
in Java, req.body
in Node.js, request.form
in Flask).
Ensure that the form data is properly validated and sanitized in the backend script to prevent security vulnerabilities.
- Sending emails
Each backend will have a different method for sending emails. Use the respective libraries or frameworks available for each technology.
Pro tips:
- You can also embed radio buttons or checkboxes in the form. Here I aimed for simplicity, focusing on the email and message, so there aren’t checkboxes and radio buttons.
- Consider implementing CAPTCHA to prevent spam submissions and confirm that the form is being filled out by a human. Later, I’ll show you how to integrate Google’s reCAPTCHA.
- It’s best to use a proper email-sending service like Email Sending by Mailtrap Email Delivery Platform to ensure your emails securely land at the desired address.
HTML email form with CSS styles
Without CSS, the form looks bland and might actually affect the conversions. So, I’ll make it more elegant, and the exemplary form below contains Name, Email, and Message fields, plus the Submit button.
The HTML form
<!DOCTYPE html>
<html>
<head>
<title>Contact Form</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="container">
<form id="contact-form" action="process-form.php" method="post">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message:</label>
<textarea id="message" name="message" rows="4" required></textarea>
</div>
<div class="form-group">
<input type="submit" value="Submit">
</div>
</form>
</div>
</body>
</html>
Quick Explainer:
- HTML Structure: The form is wrapped in a
div
with a classcontainer
for styling purposes. Each input field is enclosed in adiv
with a classform-group
for better control over spacing and layout. - Required Fields: The
required
attribute in the input fields ensures that the form cannot be submitted without filling these fields.
The CSS (style.css
)
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.container {
width: 70%;
margin: 30px auto;
padding: 20px;
background: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input[type="text"],
.form-group input[type="email"],
.form-group textarea {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
.form-group input[type="submit"] {
background-color: #5cb85c;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.form-group input[type="submit"]:hover {
background-color: #4cae4c;
}
Quick Explainer:
- The
body
style sets the font and background color of the page. - The
container
class styles the form’s container with a white background, centered alignment, and a subtle box shadow for a modern look. - The
form-group
class provides spacing between each form element. - Input fields (
text
,email
,textarea
) are styled to take full width with some padding and border-radius for a pleasant rounded corner look. - I changed the submit button type a bit. It’s styled with a green background color, which changes to a slightly darker green on hover for a subtle interactive effect.
Reminder: Replace process-form.php
(placeholder) in the form’s action
attribute with the actual script that will process the form data.
JavaScript to enhance the form behavior
HTML provides only basic validation attributes. Whereas, JavaScript allows for more dynamic and responsive validation that can improve user experience. But note that this isn’t by any means a security measure.
However, it’s a much better approach to handling the form code and it can markedly improve user experience. For example, they won’t need to wait for the web page to refresh to see if the submission was successful.
Now, to create a JavaScript-enhanced HTML email form that works seamlessly with various backend technologies (like Laravel, Java, Node.js, Python, and C#), I’ll focus on two main aspects:
- Form validation
- AJAX submission
Check the following code to see how it’s done.
Form validation
document.getElementById('contact-form').addEventListener('submit', function(event) {
var nameInput = document.getElementById('name').value.trim();
var emailInput = document.getElementById('email').value.trim();
var messageInput = document.getElementById('message').value.trim();
var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // Simple email regex pattern
if (nameInput === '') {
alert('Please enter your name.');
event.preventDefault();
} else if (!emailPattern.test(emailInput)) {
alert('Please enter a valid email address.');
event.preventDefault();
} else if (messageInput === '') {
alert('Please enter your message.');
event.preventDefault();
}
});
Pro Tip:
The script above relies on a simple regex to validate an email, and it works for exemplary purposes. But on production, assuming you’re getting a lot of submissions, it may return false positives or false negatives, unless the regex is a mile long.
To offset that, consider using a proper validation library such as:
Submitting form data with AJAX
I made script below universal so that it dynamically adapts to the server-side technologies.
document.getElementById('contact-form').addEventListener('submit', function(event) {
event.preventDefault();
var formData = new FormData(this);
var actionUrl = this.getAttribute('action'); // Dynamically get the action URL
var xhr = new XMLHttpRequest();
xhr.open('POST', actionUrl, true);
xhr.onload = function () {
if (xhr.status === 200) {
alert('Email sent successfully!');
} else {
alert('An error occurred while sending the email.');
}
};
xhr.send(formData);
});
Quick Notes:
- Dynamic Action URL: Instead of hardcoding the action URL (like
send-email.php
), the script now dynamically retrieves the URL from the form’saction
attribute. This means you can set the action URL to any server-side script (PHP, Java, Node.js, etc.), and the JavaScript will adapt accordingly. - Form Data: The
FormData
object is used to capture and send all the form data, making it easy to handle on the server side, regardless of the technology used. - Ensure that the endpoint (e.g., route in Laravel, or controller in ASP.NET) specified in the form’s
action
attribute can handleFormData
sent via POST request. - Each backend technology will have its way of extracting and processing the data, but the front-end submission process remains consistent and universal.
Backed for HTML5 forms to send emails
I’ll give you backend script examples in five popular scripting languages. Note that the exemplary scripts are geared toward Mailtrap users.
HTML form email in PHP (Laravel)
The framework’s Mail class, combined with its view-based approach to email content, allows for easy and flexible email handling.
Before you proceed with the backend, you need to make some changes to frontend HTML file.
First create a view file, for example /resources/views/welcome.blade.php
. Then, ensure the specified route is matching this ‘welcome’ view.
Note: Importing CSS and JS files parts are a little bit different from the original file. By default, these assets should be in the ‘public’ folder of your Laravel project.
<link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css" >
<script src="{{ asset('js/app.js') }}" ></script>
- Set up Laravel for email sending
Before you can send emails with Laravel, you need to configure the mail settings in your .env
file. Laravel supports various mail drivers and here’s an example of setting up SMTP in the .env
file:
MAIL_MAILER=smtp
MAIL_HOST=live.smtp.mailtrap.io
MAIL_PORT=587
MAIL_USERNAME=your_mailtrap_username
MAIL_PASSWORD=your_mailtrap_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=example@example.com
MAIL_FROM_NAME="${APP_NAME}"
Replace the values with your Mailtrap mail server details. And if port 587 doesn’t work for you, use 2525.
- Create a mailable class
Laravel uses “mailable” classes to encapsulate each email’s data and configuration. You can generate a new mailable class using the Artisan command:
php artisan make:mail ContactFormMail
This command creates a new class in the App\Mail
namespace. You can define the build method to configure the email’s subject, view, and data:
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Queue\SerializesModels;
class ContactFormMail extends Mailable
{
use Queueable, SerializesModels;
public $formData;
public function __construct($data)
{
$this->formData = $data;
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'emails.contact',
);
}
}
- Create the email view
Create a view (e.g., resources/views/emails/contact.blade.php
) that Laravel will use for the email content. You can use Blade templating to dynamically populate data from the form:
<!DOCTYPE html>
<html>
<head>
<title>New Contact Form Submission</title>
</head>
<body>
<h1>Contact Form Submission</h1>
<p>Name: {{ $formData['name'] }}</p>
<p>Email: {{ $formData['email'] }}</p>
<p>Message: {{ $formData['message'] }}</p>
</body>
</html>
- Handle form submission in a controller
Important Note:
The frontend may prevent the default event when submitting the email form and just send an API call to the backend server. In this case, the API URL is /api/email.
and the API request is handled in routes/api.php
. To fix this, add the following line in the apip.php
file. I omitted the ‘/api’ because of the structure of the project.
Route::post('/email', [EmailController::class, 'sendEmail']);
In the controller that handles the form submission, use the Mail facade to send the email:
use Illuminate\Support\Facades\Mail;
use App\Mail\ContactFormMail;
public function sendEmail(Request $request)
{
$formData = $request->all();
Mail::to('receiver@example.com')->send(new ContactFormMail($formData));
// Return response or redirect
}
- Security and validation
Ensure to validate and sanitize the form data to prevent security issues like XSS and injection attacks. Laravel provides a robust validation system that you can use in your controller:
$request->validate([
'name' => 'required',
'email' => 'required|email',
'message' => 'required'
]);
For a more detailed guide on PHP email contact form, check our blog post in the link.
Handling HTML form with attachments in Laravel
- Modify the HTML form
Ensure your HTML form includes a file input and is set to send data as multipart/form-data
:
<form action="/submit-form" method="post" enctype="multipart/form-data">
<!-- Other form fields -->
<label for="attachment">File:</label>
<input type="file" id="attachment" name="attachment" accept="image/png" required>
</form>
- Update the mailable class
In your mailable class (ContactFormMail
), you’ll need to modify the build method to handle the attachment:
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [
Attachment::fromPath($this->formData['attachment'])
->as('image.png')
->withMime('image/png'),
];
}
The code checks if an attachment is included in the form data and attaches it to the email. It also creates an email attachment in Laravel by using the Attachment::fromPath()
method which specifies the file to attach via a path provided in $this->formData['attachment']
.
The ('image.png')
method sets the name of the file as it will appear in the email to 'image.png'
. Lastly, the withMime('image/png')
method defines the MIME type of the attachment to indicate that the attached file is a PNG image.
- Handle the file upload in the controller
In the controller that processes the form submission, you’ll need to handle the file upload and pass the file to the mailable:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Mail\ContactFormMail;
use Illuminate\Support\Facades\Mail;
public function sendEmail(Request $request) {
$request->validate([
'name' => 'required',
'email' => 'required | email',
'message' => 'required',
'attachment' => 'file|max:2048'
]);
$formData = $request->all();
// Handle file upload
if ($request->hasFile('attachment') && $request->file('attachment')->isValid()) {
$formData['attachment'] = $request->file('attachment');
}
Mail::to('receiver@gmail.com')->send(new ContactFormMail($formData));
}
The sendEmail
method begins by validating the incoming HTTP request, ensuring that the 'name'
, 'email'
, and 'message'
fields are provided. Also, it ensures that if an 'attachment'
is included, the file doesn’t exceed 2048 kilobytes.
When validation passes, all the data from the request, including both the form fields and files, are retrieved and stored in the $formData
variable using the all()
method.
The function checks if an attachment was uploaded and is valid by using the hasFile()
and isValid()
methods, and then it updates the $formData
array with the attachment file object.
If the attachment is present and valid, its value in the $formData
array will be an UploadedFile
instance representing the file; otherwise, it will remain as originally provided or might not exist in the array.
The next line of code sends an email to 'receiver@gmail.com'
using Laravel’s built-in Mail facade, providing a new instance of the ContactFormMail
mailable class initialized with the $formData
.
HTML form email in Java
In this section, I’ll focus on using JavaMail API, a popular and versatile library for email handling in Java applications.
- Add JavaMail dependency
The dependency needs to be added to your project. And if you’re using Maven, add the following dependency to the pom.xml
:
dependency below to the 'pom.xml':
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
- Configure the mail session
Set up the mail session properties such as the SMTP server details (use your Mailtrap credentials to replace the placeholders):
Properties props = new Properties();
props.put("mail.smtp.host", "your_mailtrap_smtp_host.io"); // SMTP Host
props.put("mail.smtp.port", "587"); // TLS Port
props.put("mail.smtp.auth", "true"); // Enable Authentication
props.put("mail.smtp.starttls.enable", "true"); // Enable STARTTLS
// Create session with authenticator
Session session = Session.getInstance(props, new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("username", "password");
}
});
- Use the
MimeMessage
class to create and send the email
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("from@example.com"));
message.addRecipient(Message.RecipientType.TO, new InternetAddress("to@example.com"));
message.setSubject("Subject Line");
// Set the email body
String emailContent = "Email body content"; // This can be HTML or plain text
message.setContent(emailContent, "text/html");
// Send the email
Transport.send(message);
System.out.println("Email sent successfully.");
} catch (MessagingException e) {
e.printStackTrace();
}
- Form data handling
To handle form data, you have to build both front-end and back-end. There are several Java frameworks that can be used to build MVC structure. Here, I’ll use Spring framework to receive form data from the frontend and handle the data to constructed and sent.
To achieve that, there are two intermediary steps:
- Move the HTML file into
/src/main/resources/templates
and the other CSS and JS files into/src/main/resources/static
. - Add
configuration/ tomcat server/
and select version of current installed tomcat server.
Assuming you have a web application that receives form submissions, you’d extract the form data and use it to construct your email content. For example:
@SpringBootApplication
@Controller
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@PostMapping("/email")
public String sayHello(@RequestParam("name") String name,
@RequestParam("email") String email,
@RequestParam("message") String message){
try {
System.out.println(name);
System.out.println(email);
System.out.println(message);
sendEmail(name, email, message, file);
return "index";
} catch (MessagingException | IOException e) {
HandleException(e);
}
}
Handling HTML form with attachments in Java
- Modify the HTML form
Ensure your HTML form includes a file input and is set to send data as multipart/form-data
:
<form action="/submit-form" method="post" enctype="multipart/form-data">
<!-- Other form fields -->
<input type="file" name="attachment">
<input type="submit" value="Submit">
</form>
- Process the attachments
In your Java backend (e.g., a servlet), you’ll need to handle the file upload.
- Attach the file to the email
Modify the email sending logic to include the attachment. You’ll use a MimeMultipart
object to combine text and attachment parts:
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("from@example.com"));
message.addRecipient(Message.RecipientType.TO, new InternetAddress("to@example.com"));
message.setSubject("Subject Line");
// Create a multipart message
Multipart multipart = new MimeMultipart();
// Create the message part
BodyPart messageBodyPart = new MimeBodyPart();
String emailContent = "Email body content"; // This can be HTML or plain text
messageBodyPart.setContent(emailContent, "text/html");
multipart.addBodyPart(messageBodyPart);
// Add the file attachment
if (fileContent != null) {
messageBodyPart = new MimeBodyPart();
DataSource source = new ByteArrayDataSource(fileContent, "application/octet-stream");
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(fileName);
multipart.addBodyPart(messageBodyPart);
}
// Send the complete message
message.setContent(multipart);
Transport.send(message);
System.out.println("Email sent successfully with attachment.");
} catch (MessagingException e) {
e.printStackTrace();
}
Important notes:
- The provided method
sendEmailWithAttachments
is designed to send an email with an attachment using JavaMail API, setting up SMTP settings for connecting to Mailtrap’s sandbox server for the outgoing email. - It configures SMTP server properties such as the host, port, authentication, and STARTTLS setting, then establishes a mail session with authentication details for the sender.
- A
MimeMessage
object is created and populated with the sender and recipient’s email addresses, along with setting the subject line for the email. - The message body is constructed using a
MimeBodyPart
, which includes a text message that contains the sender’s personal details (name, email, message), and this part is added to the Multipart container. - Another
MimeBodyPart
is dedicated to handling the file attachment, retrieving the input stream of theMultipartFile
, and setting the content type. Then, it’s appended to the multipart which accidentally contains two references tomessageBodyPart
instead of one formessageBodyPart
and one forattachmentPart
. - Finally, the entire email content including the text and attachment is sent using the
Transport.send()
method, and a confirmation message is printed to indicate successful sending. However, there’s a bug in adding both parts to the Multipart which should be corrected.
HTML form email in Node.js
Here, I’ll use Nodemailer, which is a Node.js module for email notifications. And you should easily set it up to send emails.
- Install Nodemailer
Install Nodemailer in your Node.js project by running the command below in the project directory:
npm install nodemailer
- Import and configure Nodemailer
In your Node.js script, where you handle the form submission, import Nodemailer, and set up the transporter. This transporter will be responsible for sending your emails.
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
host: 'live.smtp.mailtrap.io',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'your_mailtrap_username',
pass: 'your_mailtrap_password'
}
});
Replace the host
, user
, and pass
with your Mailtrap SMTP credentials.
- Set up email options
Define the email options including the sender, receiver, subject, and body of the email.
let mailOptions = {
from: '"Sender Name" <sender@example.com>',
to: 'receiver@example.com',
subject: 'New Form Submission',
html: '<p>This is the form submission content</p>' // HTML body
};
The html
field can be dynamically generated based on the form data received.
- Send the email
Use the transporter to send the email with the defined options.
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
});
- Handle the form data
In a real-world scenario, you’ll receive form data through an HTTP request. If you’re using Express.js, you can set up a route to handle POST requests from your form. Here’s an example containing a few intermediary steps:
- Create a new Express project
npx express-generator
For earlier Node versions, install the application generator as a global npm
package and then launch it:
npm install -g express-generator
express
For example, the following code snippet creates an Express app named myapp
. The app will be created in a folder named myapp
in the current working directory and the view engine will be set to Pug:
express --view=pug myapp
2. Install dependencies
cd myapp
npm install
3. Place the HTML, CSS, and JS files in the ‘public’ folder
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
The snippet sets up a route handler with Express’s router. The GET
method is used because this route will respond to HTTP GET requests. The first argument '/'
is the path or endpoint, which in this case is the root of the site. This means that this route will match the home page (e.g., http://www.example.com/).
The Route Handler Function (function(req, res, next))
is the second argument. It represents a callback function that gets called when an HTTP GET request is made to the specified path ('/')
. This function takes three parameters:
req
: Short for “request,” it represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, etc.res
: Short for “response,” it represents the HTTP response that an Express app sends when it receives an HTTP request.next
: A function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
Inside the callback, res.render
is called to render a view template. res.render
looks up the template engine ( Pug, EJS, Handlebars, etc.) configured in your Express app, and then render the template named 'index'
.
After the template is rendered, the resulting HTML will be sent as the response to the client. The 'index'
refers to index.*
, where *
is the file extension corresponding to the template engine used (e.g., index.pug
, index.ejs
, index.hbs
, etc.).
To summarize, when a user visits the root URL of the site, the server will respond by rendering and returning the 'index'
template, displaying the home page to the user.
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.post('/submit-form', (req, res) => {
const { name, email, message } = req.body;
// Construct the email content
let emailContent = `<p>Name: ${name}</p><p>Email: ${email}</p><p>Message: ${message}</p>`;
// Set up and send the email using Nodemailer
// ...
res.send('Form submitted successfully!');
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
Handling HTML for with attachments in Node.js
- Modify the HTML form
Ensure your HTML form includes a file input and is set to send data as multipart/form-data
:
<form action="/submit-form" method="post" enctype="multipart/form-data">
<!-- Other form fields -->
<input type="file" name="attachment">
<input type="submit" value="Submit">
</form>
- Process the attachment in Node.js
Install multer
which is a Node.js middleware for handling multipart/form-data
and it’s used for uploading files. You can install it using npm
:
npm install multer
Proceed to set up multer
in your route. If using Express.js route, here’s how to configure multer
to handle files.
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/submit-form', upload.single('attachment'), (req, res) => {
// req.file contains information about the uploaded file
// req.body contains the text fields
});
- Attach the file to the email
Check how to modify the Nodemailer setup to include the file attachment:
router.post('/email', upload.single('attachment'), (req, res) => {
let transporter = nodemailer.createTransport({
host: 'live.smtp.mailtrap.io',
port: 587,
secure: false,
auth: {
user: 'username',
pass: 'password'
}
});
const { name, email, message } = req.body;
// Construct the email content
let emailContent = `<p>Name: ${name}</p><p>Email: ${email}</p><p>Message: ${message}</p>`;
let mailOptions = {
from: '"Sender Name" <sender@example.com>',
to: 'receiver@example.com',
subject: 'New Form Submission',
html: `<p>This is the form submission content</p><br>${emailContent}`,
attachments: [
{
filename: req.file.originalname,
path: req.file.path
}
]
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
// Delete the file after sending to avoid cluttering the server
fs.unlink(req.file.path, (err) => {
if (err) throw err;
});
});
res.send('Form submitted successfully!');
});
HTML form email in Python
Python offers several libraries for sending emails, with smtplib
and email
being the most commonly used for basic email functionalities. I’ll use these libraries to show you how to send emails from an HTML form.
- Import libraries
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
- Configure Mailtrap SMTP
smtp_server = 'your_mailtrap_smtp.host.io'
smtp_port = 587
smtp_user = 'your_mailtrap_username'
smtp_password = 'your_mailtrap_password'
Don’t forget to change the placeholder credentials with your Mailtrap credentials.
- Create a MIME message
Use MIMEMultipart
to create a MIME message which can handle different parts (like text, HTML, and attachments).
msg = MIMEMultipart()
msg['From'] = smtp_user
msg['To'] = 'receiver@example.com'
msg['Subject'] = 'New Form Submission'
# Email body
body = 'This is the form submission content'
msg.attach(MIMEText(body, 'html'))
- Use
smtplib
to send the email
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_password)
server.send_message(msg)
print("Email sent successfully!")
- Handle form data
You’ll receive form data through an HTTP request. If you’re using a web framework like Flask or Django, you can set up a route to handle POST requests from your form tag:
# Example using Flask
from flask import Flask, request
app = Flask(__name__)
@app.route('/submit-form', methods=['POST'])
def submit_form():
name = request.form.get('name')
email = request.form.get('email')
message = request.form.get('message')
# Construct the email content
body = f"<p>Name: {name}</p><p>Email: {email}</p><p>Message: {message}</p>"
# Send email logic here
return 'Form submitted successfully!'
if __name__ == '__main__':
app.run(debug=True)
Note: If you need a more detailed guide on using Django instead of Flask, check our article in the link.
Handle HTML form with attachments in Python
- Modify the HTML form
Ensure your HTML form includes a file input and is set to send data as multipart/form-data
:
<form action="/email" method="post" enctype="multipart/form-data">
<!-- Other form fields -->
<input type="file" name="attachment">
<input type="submit" value="Submit">
</form>
- Process the attachment
I’ll continue with Flask as the web framework, and here’s how to handle file uploads.
from flask import Flask, request
from werkzeug.utils import secure_filename
app = Flask(__name__)
@app.route('/submit-form', methods=['POST'])
def send_email(body, path, filename):
name = request.form.get('name')
email = request.form.get('email')
message = request.form.get('message')
# Check if the post request has the file part
if 'attachment' not in request.files:
return 'No file part'
file = request.files['attachment']
if file.filename == '':
return 'No selected file'
if file:
filename = secure_filename(file.filename)
file.save(os.path.join(path, filename))
# Now you can attach this file to your email
- Attach the file to the email
Modify the email sending logic to include the file attachment. You’ll use MIMEBase
from the email
module for this:
from email.mime.base import MIMEBase
from email import encoders
# ... [previous setup code]
# Attach the file
path = ‘path/to/save/’
with open('path' + filename, 'rb') as attachment:
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
'Content-Disposition',
f'attachment; filename= {filename}',
)
msg.attach(part)
# ... [email sending logic]
Below is the full code for server.py
; run this application using the 'python server.py'
command.
from flask import Flask, render_template, request
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from werkzeug.utils import secure_filename
import os
from email.mime.base import MIMEBase
from email import encoders
app = Flask(__name__)
def send_email(body, filename):
smtp_server = 'sandbox.smtp.mailtrap.io'
smtp_port = 587
smtp_user = 'username'
smtp_password = 'password'
msg = MIMEMultipart()
msg['From'] = smtp_user
msg['To'] = 'receiver@example.com'
msg['Subject'] = 'New Form Submission'
with open('C:/email/' + filename, 'rb') as attachment:
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
'Content-Disposition',
f'attachment; filename= {filename}',
)
msg.attach(part)
# Email body
msg.attach(MIMEText(body, 'html'))
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_password)
server.send_message(msg)
print("Email sent successfully!")
@app.route('/')
def home():
return render_template('index.html')
@app.route('/email', methods=['POST'])
def post_data():
name = request.form.get('name')
email = request.form.get('email')
message = request.form.get('message')
# Check if the post request has the file part
if 'attachment' not in request.files:
return 'No file part'
file = request.files['attachment']
if file.filename == '':
return 'No selected file'
if file:
filename = secure_filename(file.filename)
file.save(os.path.join('C:/email/', filename))
# Construct the email content
body = f"<p>Name: {name}</p><p>Email: {email}</p><p>Message: {message}</p>"
send_email(body, filename)
# Send email logic here
return 'Form submitted successfully!'
if __name__ == '__main__':
app.run(debug=True)
The project structure is as follows.
Your-app —server,py
|–templates — index.html
|–static – style.css
| – script.js
HTML form email in C#
In C#, sending emails can be accomplished using the System.Net.Mail
namespace, which provides a set of classes for sending emails to an SMTP server for delivery.
- Include the namespace
using System.Net.Mail;
using System.Net;
- Configure SMTP
SmtpClient client = new SmtpClient("your_mailtrap_smtp_host.io", 587)
{
Credentials = new NetworkCredential("your_mailtrap_username", "your_mailtrap_password"),
EnableSsl = true
};
Replace the SMTP host, port, username, and password with your Mailtrap credentials.
- Create the
MailMessage
object
The object represents the email that’s going to be sent.
MailMessage mailMessage = new MailMessage
{
From = new MailAddress("your_email@example.com"),
Subject = "New Form Submission",
Body = "<p>This is the form submission content</p>",
IsBodyHtml = true
};
mailMessage.To.Add("receiver@example.com");
The IsBodyHtml
property is set to true
to indicate that the body of the email is HTML.
- Use the
SmtpClient
to send theMailMessage
try
{
client.Send(mailMessage);
Console.WriteLine("Email sent successfully.");
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in sending email: {0}", ex.ToString());
}
- Handle form data
You’ll receive form data through an HTTP request. If you’re using ASP.NET, you can set up a controller action to handle POST requests from your form. Check the example below.
[HttpPost]
public ActionResult SubmitForm(string name, string email, string message)
{
// Construct the email content
string emailContent = $"<p>Name: {name}</p><p>Email: {email}</p><p>Message: {message}</p>";
// Send email logic here
return View();
}
Handle HTML form with attachments in C#
- Modify the HTML form
Ensure your HTML form includes a file input and is set to send data as multipart/form-data
:
<form action="/YourController/SubmitForm" method="post" enctype="multipart/form-data">
<!-- Other form fields -->
<input type="file" name="attachment">
<input type="submit" value="Submit">
</form>
- Handle file uploads in ASP.NET
using System.Web;
using System.IO;
[HttpPost]
public ActionResult SubmitForm(HttpPostedFileBase attachment)
{
if (attachment != null && attachment.ContentLength > 0)
{
var fileName = Path.GetFileName(attachment.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
attachment.SaveAs(path);
// Now you can attach this file to your email
}
// Other form processing logic here
return View();
}
- Modify the sending logic to attach the file to the email
// ... [previous setup code]
if (attachment != null && attachment.ContentLength > 0)
{
var fileName = Path.GetFileName(attachment.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
attachment.SaveAs(path);
// Attach the file
mailMessage.Attachments.Add(new Attachment(path));
}
// ... [email sending logic]
// Clean up: Dispose of the message and delete the file after sending
mailMessage.Dispose();
Further reading:
Security units for HTML form
Since we’re dealing with front and backend, security measures can get pretty complicated pretty fast. So, I’ll break things down for you and provide exemplary code snippets wherever possible.
However, keep in mind that secure data-handling, both static and in-transit, isn’t a set-and-forget deal. You’ll need to get back to the code, review it from time to time, and tighten security protocols if necessary.
Front-End HTML form security
- Client-side validation: While JavaScript validation enhances user experience, remember it’s not a security measure. All validations must be rechecked on the server side.
- HTTPS: Ensure that your form is served over HTTPS to encrypt data transmitted between the client and server.
- CSRF tokens: For forms that perform actions on the server (like database updates), include Cross-Site Request Forgery (CSRF) tokens to prevent unauthorized submissions.
// In a Laravel Blade template
<form method="POST" action="/submit-form">
@csrf
<!-- form elements -->
</form>
- Captcha: Implement CAPTCHA to prevent automated submissions by bots. Here’s an example with Google’s reCAPTCHA.
<script src='https://www.google.com/recaptcha/api.js'></script>
<form action="form_submit.php" method="post">
<!-- other form elements -->
<div class="g-recaptcha" data-sitekey="your_site_key"></div>
<input type="submit" value="Submit">
</form>
Backend security
Laravel (PHP)
- Validation
$validated = $request->validate([
'email' => 'required|email',
'name' => 'required|max:255',
// other fields
]);
- Escaping output
{{ htmlspecialchars($string, ENT_QUOTES, 'UTF-8') }}
- CSRF protection: Laravel automatically generates and verifies CSRF tokens for each active user session.
- Email injection prevention: Use Laravel’s mailing classes which automatically handle email header injection attempts.
Java
- Input Validation (Using Apache Commons Validator)
EmailValidator emailValidator = EmailValidator.getInstance();
if (!emailValidator.isValid(email)) {
// Handle invalid email
}
- Prepared statements (using JDBC)
String query = "INSERT INTO users (name, email) VALUES (?, ?)";
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, name);
preparedStatement.setString(2, email);
preparedStatement.executeUpdate();
- CSRF tokens: Implement CSRF tokens in forms.
- Sanitize data: Ensure all data is sanitized before processing or storing.
Node.js
- Express validator
const { body, validationResult } = require('express-validator');
app.post('/submit-form', [
body('email').isEmail(),
body('name').not().isEmpty()
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Process form data
});
- Helmet
const helmet = require('helmet');
app.use(helmet());
- CSRF protection: Use modules like
csurf
for CSRF protection. - Sanitize input: Use libraries like
DOMPurify
to sanitize user input.
Python (Django/Flask)
- Django forms
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)
- SQLAlchemy
from sqlalchemy import create_engine
engine = create_engine('sqlite:///example.db', echo=True)
- CSRF middleware: Django/Flask has built-in CSRF protection.
- Email header injection: Ensure email headers are properly encoded and validated.
C#
- ASP.NET Validation Controls
<asp:TextBox ID="EmailTextBox" runat="server" />
<asp:RegularExpressionValidator
ControlToValidate="EmailTextBox"
ValidationExpression=".*@.*\..*"
ErrorMessage="Invalid email"
runat="server" />
- Parameterized Queries (Using ADO.NET)
string query = "INSERT INTO Users (Name, Email) VALUES (@Name, @Email)";
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@Name", name);
command.Parameters.AddWithValue("@Email", email);
command.ExecuteNonQuery();
- AntiForgery tokens: Utilize ASP.NET’s AntiForgery tokens for CSRF protection.
- Input encoding: Encode user inputs to prevent XSS attacks.
General security tips
- Error Handling (example in Node.js)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
- Security headers (example in Express.js):
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
// other directives
}
}));
- Logging: Maintain logs for monitoring and debugging purposes, but ensure they don’t contain sensitive data.
Testing emails with Mailtrap Testing
Email Testing is another inseparable part of Mailtrap Email Delivery Platform, which provides you with a safe environment to inspect emails in staging (web development and QA environments) without the risk of spamming anybody.
Here’s what you get:
- Fake SMTP Server
- HTML/CSS check (with almost any email client)
- Spam score check
- API for QA automation
- Ready-to-use integrations in 20+ languages (Ruby, Python, PHP, Node.js, .Net, etc.)
- Emails preview
- Multiple inboxes for different projects and stages
- User management, SSO
Now, why would you want to test the emails you’re getting from a form?
Simply, there are three key reasons:
- Understand if the form emails are displaying properly.
- See if the emails include all the relevant data.
- Make sure none of the data got compromised in transit.
Also, I want to stress that you can integrate Mailtrap with SMTP or API. Here’s how to do it, and I assume that you’re already a user.
SMTP integration
I’ll use the Laravel example to show you how it goes. If you’re on a default Laravel setup, you can just change the values in the ‘.env’ file in the root directory of your project.
MAIL_MAILER=smtp
MAIL_HOST=sandbox.smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_mailtrap_username
MAIL_PASSWORD=your_mailtrap_password
The same principle applies to any other language/framework you’re using. It’s just changing the SMTP credentials – host endpoint, port, username, and password – from Email Sending to Email Testing.
And remember that there’s an in-app drop-down with 20+ ready-made integrations, you can just copy-paste.
API integration
You can use the API to fetch emails, check their content, sender, recipient, and other parameters programmatically.
First, you need to get your API token located under Settings > API Tokens.
Then, you can use the token to authenticate your API requests. Check two basic examples of API usage. They’re in PHP:
Fetch inbox attributes:
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mailtrap.io/api/accounts/account_id/inboxes/inbox_id",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Api-Token: 123"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Show email message:
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mailtrap.io/api/accounts/account_id/inboxes/inbox_id/messages/message_id",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Api-Token: 123"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
If you need more examples and API actions – check the official docs here.
Wrapping up
Seemingly simple, to me, the HTML email form is a fascinating intersection of design, functionality, and security. I hope to have helped you get a much better understanding of how to create and implement a form that handles data safely. Then, send that data to your email.
And yes, the trickery is in all the intricacies of client and server-side scripting. But mark my words, when you see it all up and running smoothly, the joy of success is immense.
If you’re interested in building email contact forms in a variety of other programming languages, then check out our YouTube channel where we have multiple contact form tutorials published: