I have a working Contact Us html form and a working google Apps Script that handles the emailing of the forms data. The form is shown below:
<!DOCTYPE html>
<html>
<head>
</head>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: #F0F0F0;
}
.container {
margin: 50px auto;
width: 100%;
max-width: 800px;
border-radius: 20px;
background-color: #5C7887;
padding: 20px;
text-align: center;
}
.row {
display: flex;
margin-bottom: 10px;
}
.row:nth-child(6) {
width: 100%;
}
.row:last-child {
display: block;
}
.col {
flex-basis: 50%;
padding: 5px;
}
.col:first-child {
padding-right: 10px;
}
.col:last-child {
padding-left: 10px;
}
label {
display: block;
font-weight: bold;
color: #FFFFFF;
margin-bottom: 5px;
}
input[type="text"], select, textarea {
width: 100%;
border-radius: 5px;
padding: 5px;
border: none;
background-color: #FFFFFF;
text-align: center;
}
textarea#description {
text-align: left;
}
select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 10"><path d="M0 0 L15 10 L30 0"></path></svg>');
background-position: calc(100% - 10px) center;
background-repeat: no-repeat;
background-size: 10px 10px;
padding-right: 20px;
text-align: center;
}
.file-upload {
position: relative;
overflow: hidden;
display: inline-block;
background-color: white;
color: #5C7887;
border-radius: 5px;
padding: 10px;
cursor: pointer;
font-weight: bold;
border: none;
font-family: sans-serif;
}
.file-upload input[type=file] {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
.file-counter {
margin-left: 0px;
color: white;
}
button[type=submit], .file-upload {
display: block;
margin: auto;
padding: 3px;
border-radius: 5px;
background-color: white;
color: #5C7887;
font-weight: bold;
border: none;
cursor: pointer;
}
button[type="submit"] {
background-color: #fff;
color: #5C7887;
border: none;
border-radius: 5px;
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
button[type="submit"]:hover, .file-upload:hover {
background-color: #67C2F3;
color: #fff;
}
@media screen and (max-width: 600px) {
.row {
flex-direction: column;
}
.col {
flex-basis: 100%;
padding: 5px 0;
}
.col:first-child {
padding-right: 0;
}
.col:last-child {
padding-left: 0;
}
.file-upload, button[type=submit] {
width: 100%;
}
}
</style>
<body>
<div class="container">
<form action="https://script.google.com/macros/s/mycustomURL" method="post" enctype="multipart/form-data">
<div class="row">
<div class="col">
<label for="first-name">First Name:</label>
<input type="text" id="first-name" name="first-name">
</div>
<div class="col">
<label for="last-name">Last Name:</label>
<input type="text" id="last-name" name="last-name">
</div>
</div>
<div class="row">
<div class="col">
<label for="phone">Phone Number:</label>
<input type="text" id="phone" name="phone" placeholder="(xxx) xxx-xxxx" maxlength="14">
</div>
<div class="col">
<label for="email">Email:</label>
<input type="text" id="email" name="email">
</div>
</div>
<div class="row">
<div class="col">
<label for="street">Street:</label>
<input type="text" id="street" name="street">
</div>
<div class="col">
<label for="city">City:</label>
<input type="text" id="city" name="city">
</div>
</div>
<div class="row">
<div class="col">
<label for="state">State:</label>
<select id="state" name="state">
</select>
</div>
<div class="col">
<label for="zip">Zip Code:</label>
<input type="text" id="zip" name="zip" oninput="this.value = this.value.replace(/[^0-9]/g, '').slice(0, 5)">
</div>
</div>
<div class="row">
<div class="col">
<label for="Service-Needed">Service Needed:</label>
<select id="Service-Needed" name="Service-Needed" required>
<option value="" selected>Service Needed</option>
<option value="A">A Enclosures</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>
</div>
<div class="col">
<label for="files">Files:</label>
<div class="file-upload">
Upload a File
<input type="file" id="files" name="files[]" multiple>
</div>
<span class="file-counter">0 files selected</span>
</div>
</div>
<div class="row" style="text-align: center; flex-direction: column;">
<label for="description">Description:</label>
<textarea id="description" name="description" style="height: 200px;"></textarea>
</div>
<div class="row">
<div class="col">
<button type="submit" id="submit-btn">Submit</button>
</div>
</div>
</form>
<p id="message" style="display: none;"></p>
</div>
<script>
// Get the input field and the counter element
const input = document.getElementById('files');
const counter = document.querySelector('.file-counter');
// Add an event listener to the input field to update the counter when files are selected
input.addEventListener('change', updateCounter);
function updateCounter() {
// Get the number of files selected
const count = input.files.length;
// Update the counter text
if (count === 0) {
counter.textContent = 'No files selected';
} else if (count === 1) {
counter.textContent = '1 file selected';
} else {
counter.textContent = count + ' files selected';
}
}
</script>
<script>
// Get the phone input field
const phoneInput = document.getElementById('phone');
// Add event listener for input changes
phoneInput.addEventListener('input', function (event) {
// Remove all non-numeric characters from input value
let phoneValue = event.target.value.replace(/\D/g, '');
// Limit input value to 10 characters
phoneValue = phoneValue.slice(0, 10);
// Format input value to (xxx) xxx-xxxx
if (phoneValue.length >= 3) {
phoneValue = `(${phoneValue.slice(0, 3)}) ${phoneValue.slice(3)}`;
}
if (phoneValue.length >= 9) {
phoneValue = `${phoneValue.slice(0, 9)}-${phoneValue.slice(9)}`;
}
// Set input value to formatted value
event.target.value = phoneValue;
});
</script>
<script>
async function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = (error) => reject(error);
});
}
const form = document.querySelector('form');
const messageElement = document.getElementById('message');
const submitButton = document.getElementById('submit-btn');
form.addEventListener('submit', async (event) => {
event.preventDefault();
// Disable the submit button and change its text to "Sending".
submitButton.disabled = true;
submitButton.textContent = 'Sending...';
const formData = new FormData(form);
const files = formData.getAll('files[]');
const filesData = [];
for (const file of files) {
const base64 = await getBase64(file);
filesData.push({
name: file.name,
data: base64,
mimeType: file.type,
});
}
formData.set('files', JSON.stringify(filesData));
// Show "Please wait" message while sending email
messageElement.textContent = 'Please wait a moment.....';
messageElement.style.display = 'block';
messageElement.style.color = 'white';
const response = await fetch('https://script.google.com/macros/s/mycustomURL', {
method: 'POST',
body: formData,
});
const result = await response.text();
// Re-enable the submit button and change its text back to "Submit".
submitButton.disabled = false;
submitButton.textContent = 'Submit';
if (response.ok) {
messageElement.textContent = 'Thank you. Your email has been sent.';
messageElement.style.display = 'block';
messageElement.style.color = 'white';
} else {
messageElement.textContent = 'Hmmm. Something went wrong.';
messageElement.style.display = 'block';
messageElement.style.color = 'gold';
}
});
</script>
</body>
</html>
The Google Apps Script is shown below:
function doPost(e) {
var firstName = e.parameter['first-name'];
var lastName = e.parameter['last-name'];
var phone = e.parameter['phone'];
var email = e.parameter['email'];
var street = e.parameter['street'];
var city = e.parameter['city'];
var state = e.parameter['state'];
var zip = e.parameter['zip'];
var serviceNeeded = e.parameter['Service-Needed'];
var description = e.parameter['description'];
var files = JSON.parse(e.parameter['files']);
var attachments = [];
for (var i = 0; i < files.length; i++) {
attachments.push({
fileName: files[i].name,
mimeType: files[i].mimeType,
content: Utilities.base64Decode(files[i].data)
});
}
var body = "New message from " + firstName + " " + lastName + " via website:\n\n";
body += "Name: " + firstName + " " + lastName + "\n";
body += "Phone: " + phone + "\n";
body += "Email: " + email + "\n";
body += "Address: " + street + ", " + city + ", " + state + " " + zip + "\n";
body += "Service Needed: " + serviceNeeded + "\n";
body += "Description: " + description + "\n";
try {
// Add the attachments if files were uploaded
var options = attachments.length > 0 ? {attachments: attachments} : {};
GmailApp.sendEmail('recipient@test.com', 'New message from ' + firstName + ' ' + lastName + ' via website', body, options);
return ContentService.createTextOutput("success");
} catch (error) {
Logger.log("Error sending email: " + error);
return ContentService.createTextOutput("error");
}
}
for the life of me, i can't figure out what is holding up a submission when there is no attachments involved. It works GREAT when attachments are sent, but i get nothing when there isnt attachments. The form even completes the a run and displays the text that the email has been sent, but its not true.
i have tried adding an IF function to my google app script to check if there is an attachment, but that did not work. I tried putting it on my last where it handles file uploads as well, but it did nothing. The only way it works is if the google apps script doesn't handle attachments, but that would be against my end goal. I need the form and script to send user data with or without attachments.
Google Apps Script If function:
for (var i = 0; i < files.length; i++) {
attachments.push({
fileName: files[i].name,
mimeType: files[i].mimeType,
content: Utilities.base64Decode(files[i].data)
});
}
...
try {
// Add the attachments if files were uploaded
var options = attachments.length > 0 ? {attachments: attachments} : {};
html contact us form if function:
const formData = new FormData(form);
const files = formData.getAll('files[]');
const filesData = [];
if (files.length > 0) {
for (const file of files) {
const base64 = await getBase64(file);
filesData.push({
name: file.name,
data: base64,
mimeType: file.type,
});
}
formData.delete('files[]');
formData.set('files', JSON.stringify(filesData));
}
When I saw your showing script, I thought that the reason for your current issue might be due to const files = formData.getAll('files[]');
. Because, in this case, the length of files
is 1 even when the file is not selected. In this case, the attachment file with no content is used. I thought that this might be the reason for your current issue.
In order to remove this issue, how about the following modification?
const files = formData.getAll('files[]');
const files = formData.getAll('files[]').filter(e => e.size > 0);
files
is 0. So, I thought that the script can be worked without the attachment file.