Static Site Contact Form Email Integration (GitHub Pages)
This guide demonstrates how to implement a contact form on a static website that sends emails without server-side code or redirects, using Google Forms as the backend.
đź”— View Demo Contact Form
Why This Approach?
- No backend server required
- Free to implement and maintain
- No third-party form service dependencies
- Works with static site hosting (GitHub Pages, Netlify, etc.)
- Reliable Google infrastructure
- Responses can be managed via Google Sheets
- Easy email notification setup
Implementation Guide
First, create your base HTML form structure that matches your design requirements:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <form>
<div class="form-group">
<label>Name:</label>
<input type="text" name="name">
</div>
<div class="form-group">
<label>Email:</label>
<input type="email" name="email">
</div>
<div class="form-group">
<label>Message:</label>
<textarea name="message"></textarea>
</div>
<button type="submit">Send Message</button>
</form>
|
- Go to Google Forms
- Create a new form
- Add fields that correspond to your HTML form
To map your form fields to Google Form fields:
- Open your Google Form
- Click “Get pre-filled link”
- Fill in any test data
- Click “Get Link”
- Analyze the URL to find field IDs:
1
2
3
| https://docs.google.com/forms/d/e/[FORM-ID]/viewform?entry.123456789=nameexample&entry.987654321=emailexample&entry.987654321=messageexample
↑ ↑ ↑
Field IDs are these numbers
|
Modify your form to integrate with Google Forms:
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
| <form
id="contactForm"
target="hidden_iframe"
action="https://docs.google.com/forms/d/e/[FORM-ID]/formResponse?"
method="post"
>
<div class="form-group">
<label>Name:</label>
<input type="text" name="entry.123456789" required>
</div>
<div class="form-group">
<label>Email:</label>
<input type="email" name="entry.987654321" required>
</div>
<div class="form-group">
<label>Message:</label>
<textarea name="entry.456789123" required></textarea>
</div>
<button type="submit">Send Message</button>
</form>
<!-- Hidden iframe to prevent redirect -->
<iframe
name="hidden_iframe"
id="hidden_iframe"
style="display: none;"
onload="if(submitted) {handleSubmission()}"
></iframe>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| let submitted = false;
function handleSubmission() {
// Hide form
document.getElementById('contactForm').style.display = 'none';
// Show success message
const successMessage = document.createElement('div');
successMessage.className = 'success-message';
successMessage.innerHTML = `
<h3>Thank you!</h3>
<p>Your message has been sent successfully.</p>
`;
document.getElementById('contactForm').parentNode.appendChild(successMessage);
}
// Optional: Add loading state
document.getElementById('contactForm').addEventListener('submit', function() {
submitted = true;
const button = this.querySelector('button[type="submit"]');
button.disabled = true;
button.innerHTML = 'Sending...';
});
|
6. Add Basic CSS Styling
1
2
3
4
5
6
7
8
9
10
11
12
| .success-message {
text-align: center;
padding: 2rem;
background: #f8f9fa;
border-radius: 0.5rem;
margin: 2rem 0;
}
.success-message h3 {
color: #28a745;
margin-bottom: 1rem;
}
|
Extended Setting Up Email Notifications
Step 1: Access Google Apps Script
- Open your Google Form responses spreadsheet
- Click on “Extensions” in the top menu
- Select “Apps Script”
Step 2: Add the Notification Script
- In the Apps Script editor, replace any existing code with this script:
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
82
83
84
85
86
87
88
| function sendEmailNotification(e) {
try {
// Get the active spreadsheet
const ss = SpreadsheetApp.getActiveSpreadsheet();
if (!ss) {
Logger.log('Could not find active spreadsheet');
return;
}
// List all sheets and their names for debugging
const sheets = ss.getSheets();
Logger.log('Available sheets:');
sheets.forEach(sheet => Logger.log(sheet.getName()));
// Get the first sheet if name doesn't match
const sheet = ss.getSheetByName('react-static-site-contact-section (Responses)') || ss.getSheets()[0];
if (!sheet) {
Logger.log('Could not find any sheets');
return;
}
Logger.log('Using sheet: ' + sheet.getName());
// Get the last row with data
const lastRow = sheet.getLastRow();
if (lastRow <= 1) {
Logger.log('No data found in sheet');
return;
}
// Get the last row's data
const lastRowData = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn()).getValues()[0];
// Extract data from the last submission
const timestamp = lastRowData[0];
const name = lastRowData[1];
const email = lastRowData[2];
const message = lastRowData[3];
// Create email content
const emailSubject = 'New Contact Form Submission';
const emailBody = `
New contact form submission received:
Timestamp: ${timestamp}
Name: ${name}
Email: ${email}
Message: ${message}
This is an automated notification.
`;
// Send email to your address
const YOUR_EMAIL = 'example@example.com'; // Replace with your email address
MailApp.sendEmail(YOUR_EMAIL, emailSubject, emailBody);
Logger.log('Email sent successfully');
} catch (error) {
Logger.log('Error in sendEmailNotification: ' + error.toString());
throw error;
}
}
// Function to create trigger
function createFormTrigger() {
try {
// Delete existing triggers to avoid duplicates
const triggers = ScriptApp.getProjectTriggers();
triggers.forEach(trigger => ScriptApp.deleteTrigger(trigger));
// Create new trigger to run on form submit
ScriptApp.newTrigger('sendEmailNotification')
.forSpreadsheet(SpreadsheetApp.getActive())
.onFormSubmit()
.create();
Logger.log('Trigger created successfully');
} catch (error) {
Logger.log('Error in createFormTrigger: ' + error.toString());
throw error;
}
}
// Test function to manually run the notification
function testEmailNotification() {
sendEmailNotification();
Logger.log('Test completed');
}
|
- Replace
'your.email@example.com'
with the email address where you want to receive notifications - Save the script by clicking the disk icon or pressing Ctrl/Cmd + S
Step 4: Set Up Authorization
- Click the “Run” button to run the
createFormTrigger
function - Google will prompt you to authorize the script
- Click “Review Permissions”
- Select your Google account
- Click “Advanced” and then “Go to [Your Project Name] (unsafe)”
- Click “Allow”
Step 5: Test the Setup
- In the Apps Script editor, select
testEmailNotification
from the function dropdown - Click the “Run” button
- Check your email to confirm you received the test notification
- Submit a test response through your contact form
- Verify that you receive the email notification
Received Email
Troubleshooting
Common Issues and Solutions:
- No Email Notifications
- Check if the trigger is set up: View -> Triggers in Apps Script
- Verify your email address is correct in the code
- Check the Apps Script execution logs for errors
- Authorization Errors
- Make sure you completed the authorization process
- Check if you have permission to use Gmail services
- Try running the test function again
- Script Errors
- View the execution log in Apps Script
- Verify the spreadsheet is still connected to the form
- Check if column numbers match your form fields
Important Considerations
Security
- Google Forms submissions are public by default
- Don’t use for sensitive information
- Consider reCAPTCHA integration for spam prevention
Limitations
- No direct file uploads
- Can’t customize success/error responses from Google
- May need CORS consideration
- Form spam protection is limited
Best Practices
- Always validate inputs client-side
- Implement rate limiting if possible
- Add loading states for better UX
- Test thoroughly across browsers
- Consider accessibility features
Advanced Customization
Custom Success Messages
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| function handleSubmission() {
// Animate form fadeout
const form = document.getElementById('contactForm');
form.style.opacity = '0';
form.style.transition = 'opacity 0.5s ease';
setTimeout(() => {
form.style.display = 'none';
showCustomSuccess();
}, 500);
}
function showCustomSuccess() {
// Add your custom success UI here
}
|
Loading States
1
2
3
4
5
6
7
8
| function setLoadingState(isLoading) {
const button = document.querySelector('button[type="submit"]');
const loadingText = 'Sending...';
const normalText = 'Send Message';
button.disabled = isLoading;
button.innerHTML = isLoading ? loadingText : normalText;
}
|
License
This implementation guide is available under the MIT License. Feel free to use, modify, and distribute as needed.