
Complete PHP Contact Form with Gmail API Tutorial: Send Emails Like a Pro
Table of Contents
What You'll Build
By the end of this tutorial, you'll have a fully functional PHP contact form that sends professional emails using Gmail API, complete with OAuth authentication, error handling, and security best practices.
Building a reliable contact form is essential for any website, but using Gmail API instead of traditional SMTP gives you better deliverability, enhanced security, and professional email handling. This comprehensive guide walks you through every step.
Why Use Gmail API for Contact Forms?
Gmail API offers significant advantages over traditional SMTP methods for sending emails from your contact forms:
Advantages of Gmail API
- • Higher email deliverability rates (99.9%)
- • No SMTP server configuration required
- • Built-in spam protection and filtering
- • OAuth 2.0 security (no password storage)
- • Better reputation and trust with email providers
- • Detailed delivery tracking and analytics
- • Handles attachments and HTML emails seamlessly
SMTP Limitations
- • Often blocked by hosting providers
- • Higher chance of emails ending up in spam
- • Requires server configuration and maintenance
- • Security risks with stored passwords
- • Limited sending quotas and restrictions
- • No built-in analytics or tracking
- • Potential IP blacklisting issues
Prerequisites and Requirements
Before we begin, make sure you have the following setup and knowledge:
Technical Requirements
Server Requirements:
- • PHP 7.4 or higher
- • Composer (dependency manager)
- • cURL extension enabled
- • OpenSSL extension
- • JSON extension
Required Accounts:
- • Google account (Gmail)
- • Google Cloud Console access
- • Web hosting with PHP support
- • Domain name (for production)
- • SSL certificate (recommended)
Setting Up Google Cloud Console
The first step is to create a project in Google Cloud Console and enable the Gmail API. Follow these detailed steps:
Create a New Google Cloud Project
Start by creating a new project in Google Cloud Console to manage your Gmail API credentials.
Enable Gmail API
Enable the Gmail API for your project to allow sending emails through Google's servers.
Gmail API Configuration
Now we need to configure the Gmail API and set up the necessary scopes and permissions:
Configure OAuth Consent Screen
Set up the OAuth consent screen that users will see when authorizing your application.
Important OAuth Scope
For contact forms, you only need the gmail.send scope, which allows your application to send emails on behalf of the authenticated user. This is the most restrictive scope that still allows email sending.
OAuth 2.0 Credentials Setup
Create OAuth 2.0 Credentials
Generate the credentials that your PHP application will use to authenticate with Gmail API.
Security Best Practice
Never commit your OAuth credentials to version control! Store them securely and use environment variables in production.
Authorized Redirect URIs Example:
Development: http://localhost/contact-form/callback.php
Production: https://yourdomain.com/contact-form/callback.php
PHP Environment Setup
Let's set up the PHP environment and install the necessary dependencies using Composer:
Install Google Client Library
Use Composer to install the official Google API client library for PHP.
{
"require": {
"google/apiclient": "^2.12",
"monolog/monolog": "^2.8"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}# Install Composer if not already installed
curl -sS https://getcomposer.org/installer | php
php composer.phar install
# Or if Composer is globally installed
composer installBuilding the Contact Form HTML
Let's create a beautiful, responsive contact form with proper validation and user experience:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Us - Professional Contact Form</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
padding: 40px;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
width: 100%;
max-width: 600px;
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
font-size: 2.5em;
font-weight: 300;
}
.form-group {
margin-bottom: 25px;
}
label {
display: block;
margin-bottom: 8px;
color: #555;
font-weight: 500;
font-size: 14px;
}
input, textarea {
width: 100%;
padding: 15px;
border: 2px solid #e1e1e1;
border-radius: 10px;
font-size: 16px;
transition: all 0.3s ease;
background: #fafafa;
}
input:focus, textarea:focus {
outline: none;
border-color: #667eea;
background: white;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
textarea {
resize: vertical;
min-height: 120px;
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 15px 40px;
border: none;
border-radius: 10px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
width: 100%;
text-transform: uppercase;
letter-spacing: 1px;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
}
.btn:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
.alert {
padding: 15px;
border-radius: 10px;
margin-bottom: 25px;
font-weight: 500;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 2px solid #c3e6cb;
}
.alert-error {
background: #f8d7da;
color: #721c24;
border: 2px solid #f5c6cb;
}
.loading {
display: none;
text-align: center;
padding: 20px;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #667eea;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 15px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@media (max-width: 768px) {
.container {
padding: 25px;
margin: 10px;
}
h1 {
font-size: 2em;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Contact Us</h1>
<div id="alert-container"></div>
<div id="loading" class="loading">
<div class="spinner"></div>
<p>Sending your message...</p>
</div>
<form id="contactForm" method="POST" action="process-contact.php">
<div class="form-group">
<label for="name">Full Name *</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email Address *</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="subject">Subject *</label>
<input type="text" id="subject" name="subject" required>
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" required
placeholder="Tell us how we can help you..."></textarea>
</div>
<button type="submit" class="btn" id="submitBtn">
Send Message
</button>
</form>
</div>
<script>
document.getElementById('contactForm').addEventListener('submit', function(e) {
e.preventDefault();
const form = this;
const formData = new FormData(form);
const submitBtn = document.getElementById('submitBtn');
const loading = document.getElementById('loading');
const alertContainer = document.getElementById('alert-container');
// Show loading state
submitBtn.disabled = true;
loading.style.display = 'block';
form.style.display = 'none';
alertContainer.innerHTML = '';
// Send form data
fetch('process-contact.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
loading.style.display = 'none';
form.style.display = 'block';
submitBtn.disabled = false;
if (data.success) {
alertContainer.innerHTML = `
<div class="alert alert-success">
${data.message}
</div>
`;
form.reset();
} else {
alertContainer.innerHTML = `
<div class="alert alert-error">
${data.message}
</div>
`;
}
})
.catch(error => {
loading.style.display = 'none';
form.style.display = 'block';
submitBtn.disabled = false;
alertContainer.innerHTML = `
<div class="alert alert-error">
An error occurred. Please try again later.
</div>
`;
});
});
</script>
</body>
</html>PHP Backend Implementation
Now let's build the PHP backend that handles form submissions and integrates with Gmail API:
<?php
// config.php - Configuration settings
// Environment settings
define('ENVIRONMENT', 'development'); // 'development' or 'production'
define('DEBUG_MODE', true);
// Gmail API Configuration
define('GOOGLE_CLIENT_ID', 'your-client-id.googleusercontent.com');
define('GOOGLE_CLIENT_SECRET', 'your-client-secret');
define('GOOGLE_REDIRECT_URI', 'http://localhost/contact-form/callback.php');
// Email settings
define('FROM_EMAIL', 'your-email@gmail.com');
define('FROM_NAME', 'Your Website Name');
define('TO_EMAIL', 'contact@yourwebsite.com');
// Security settings
define('CSRF_TOKEN_NAME', 'csrf_token');
define('SESSION_NAME', 'contact_form_session');
// Rate limiting
define('MAX_REQUESTS_PER_HOUR', 5);
define('MAX_REQUESTS_PER_DAY', 20);
// Logging
define('LOG_FILE', __DIR__ . '/logs/contact-form.log');
define('ERROR_LOG_FILE', __DIR__ . '/logs/error.log');
// Create logs directory if it doesn't exist
if (!is_dir(__DIR__ . '/logs')) {
mkdir(__DIR__ . '/logs', 0755, true);
}
// Start session
session_name(SESSION_NAME);
session_start();
// Error reporting based on environment
if (ENVIRONMENT === 'development') {
error_reporting(E_ALL);
ini_set('display_errors', 1);
} else {
error_reporting(0);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', ERROR_LOG_FILE);
}
?><?php
// GmailService.php - Gmail API Service
require_once 'config.php';
require_once 'vendor/autoload.php';
use Google\Client;
use Google\Service\Gmail;
use Google\Service\Gmail\Message;
class GmailService {
private $client;
private $service;
private $logger;
public function __construct() {
$this->setupLogger();
$this->initializeGoogleClient();
}
private function setupLogger() {
$this->logger = new Monolog\Logger('GmailService');
$handler = new Monolog\Handler\RotatingFileHandler(LOG_FILE, 0, Monolog\Logger::INFO);
$this->logger->pushHandler($handler);
}
private function initializeGoogleClient() {
$this->client = new Client();
$this->client->setClientId(GOOGLE_CLIENT_ID);
$this->client->setClientSecret(GOOGLE_CLIENT_SECRET);
$this->client->setRedirectUri(GOOGLE_REDIRECT_URI);
$this->client->addScope(Gmail::GMAIL_SEND);
$this->client->setAccessType('offline');
$this->client->setPrompt('consent');
// Load access token if exists
$tokenPath = $this->getTokenPath();
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$this->client->setAccessToken($accessToken);
// Refresh token if expired
if ($this->client->isAccessTokenExpired()) {
if ($this->client->getRefreshToken()) {
$this->client->fetchAccessTokenWithRefreshToken($this->client->getRefreshToken());
file_put_contents($tokenPath, json_encode($this->client->getAccessToken()));
} else {
throw new Exception('Access token expired and no refresh token available');
}
}
$this->service = new Gmail($this->client);
}
}
public function getAuthUrl() {
return $this->client->createAuthUrl();
}
public function handleCallback($authCode) {
try {
$accessToken = $this->client->fetchAccessTokenWithAuthCode($authCode);
if (array_key_exists('error', $accessToken)) {
throw new Exception('Error fetching access token: ' . $accessToken['error']);
}
// Save token
$tokenPath = $this->getTokenPath();
file_put_contents($tokenPath, json_encode($accessToken));
$this->service = new Gmail($this->client);
$this->logger->info('OAuth authentication successful');
return true;
} catch (Exception $e) {
$this->logger->error('OAuth callback error: ' . $e->getMessage());
return false;
}
}
public function isAuthenticated() {
return isset($this->service) && !$this->client->isAccessTokenExpired();
}
public function sendEmail($to, $subject, $htmlBody, $textBody = null) {
if (!$this->isAuthenticated()) {
throw new Exception('Gmail service not authenticated');
}
try {
$message = $this->createMessage($to, $subject, $htmlBody, $textBody);
$result = $this->service->users_messages->send('me', $message);
$this->logger->info('Email sent successfully', [
'to' => $to,
'subject' => $subject,
'message_id' => $result->getId()
]);
return $result;
} catch (Exception $e) {
$this->logger->error('Failed to send email: ' . $e->getMessage(), [
'to' => $to,
'subject' => $subject
]);
throw $e;
}
}
private function createMessage($to, $subject, $htmlBody, $textBody = null) {
$boundary = uniqid(rand(), true);
$rawMessage = "From: " . FROM_NAME . " <" . FROM_EMAIL . ">\r\n";
$rawMessage .= "To: {$to}\r\n";
$rawMessage .= "Subject: {$subject}\r\n";
$rawMessage .= "MIME-Version: 1.0\r\n";
$rawMessage .= "Content-Type: multipart/alternative; boundary={$boundary}\r\n\r\n";
// Text version
if ($textBody) {
$rawMessage .= "--{$boundary}\r\n";
$rawMessage .= "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
$rawMessage .= $textBody . "\r\n\r\n";
}
// HTML version
$rawMessage .= "--{$boundary}\r\n";
$rawMessage .= "Content-Type: text/html; charset=UTF-8\r\n\r\n";
$rawMessage .= $htmlBody . "\r\n\r\n";
$rawMessage .= "--{$boundary}--";
$message = new Message();
$message->setRaw(base64url_encode($rawMessage));
return $message;
}
private function getTokenPath() {
return __DIR__ . '/tokens/gmail_token.json';
}
}
// Helper function for base64url encoding
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
?>Email Sending Logic
<?php
// process-contact.php - Contact form processing
require_once 'config.php';
require_once 'GmailService.php';
header('Content-Type: application/json');
class ContactFormProcessor {
private $gmailService;
private $errors = [];
private $data = [];
public function __construct() {
$this->gmailService = new GmailService();
}
public function processRequest() {
try {
// Check if authenticated with Gmail
if (!$this->gmailService->isAuthenticated()) {
return $this->jsonResponse(false, 'Gmail authentication required. Please contact administrator.');
}
// Validate request method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
return $this->jsonResponse(false, 'Invalid request method.');
}
// Rate limiting check
if (!$this->checkRateLimit()) {
return $this->jsonResponse(false, 'Too many requests. Please try again later.');
}
// Validate and sanitize input
if (!$this->validateInput()) {
return $this->jsonResponse(false, 'Please fix the following errors: ' . implode(', ', $this->errors));
}
// Send email
$emailSent = $this->sendContactEmail();
if ($emailSent) {
$this->logSubmission();
return $this->jsonResponse(true, 'Thank you! Your message has been sent successfully. We\'ll get back to you soon.');
} else {
return $this->jsonResponse(false, 'Failed to send email. Please try again later.');
}
} catch (Exception $e) {
error_log('Contact form error: ' . $e->getMessage());
return $this->jsonResponse(false, 'An unexpected error occurred. Please try again later.');
}
}
private function validateInput() {
// Get and sanitize input data
$this->data['name'] = $this->sanitizeInput($_POST['name'] ?? '');
$this->data['email'] = $this->sanitizeInput($_POST['email'] ?? '');
$this->data['subject'] = $this->sanitizeInput($_POST['subject'] ?? '');
$this->data['message'] = $this->sanitizeInput($_POST['message'] ?? '');
// Validate required fields
if (empty($this->data['name'])) {
$this->errors[] = 'Name is required';
} elseif (strlen($this->data['name']) < 2) {
$this->errors[] = 'Name must be at least 2 characters long';
} elseif (strlen($this->data['name']) > 100) {
$this->errors[] = 'Name must not exceed 100 characters';
}
if (empty($this->data['email'])) {
$this->errors[] = 'Email is required';
} elseif (!filter_var($this->data['email'], FILTER_VALIDATE_EMAIL)) {
$this->errors[] = 'Please enter a valid email address';
}
if (empty($this->data['subject'])) {
$this->errors[] = 'Subject is required';
} elseif (strlen($this->data['subject']) > 200) {
$this->errors[] = 'Subject must not exceed 200 characters';
}
if (empty($this->data['message'])) {
$this->errors[] = 'Message is required';
} elseif (strlen($this->data['message']) < 10) {
$this->errors[] = 'Message must be at least 10 characters long';
} elseif (strlen($this->data['message']) > 5000) {
$this->errors[] = 'Message must not exceed 5000 characters';
}
// Check for spam patterns
if ($this->isSpam()) {
$this->errors[] = 'Message appears to be spam';
}
return empty($this->errors);
}
private function sanitizeInput($input) {
return trim(htmlspecialchars($input, ENT_QUOTES, 'UTF-8'));
}
private function isSpam() {
$spamKeywords = ['viagra', 'casino', 'lottery', 'winner', 'congratulations', 'click here', 'free money'];
$message = strtolower($this->data['message']);
foreach ($spamKeywords as $keyword) {
if (strpos($message, $keyword) !== false) {
return true;
}
}
// Check for excessive links
if (substr_count($message, 'http') > 2) {
return true;
}
return false;
}
private function checkRateLimit() {
$ip = $_SERVER['REMOTE_ADDR'];
$hourKey = 'rate_limit_hour_' . $ip . '_' . date('Y-m-d-H');
$dayKey = 'rate_limit_day_' . $ip . '_' . date('Y-m-d');
// Simple file-based rate limiting (in production, use Redis or database)
$hourFile = __DIR__ . '/cache/' . md5($hourKey) . '.tmp';
$dayFile = __DIR__ . '/cache/' . md5($dayKey) . '.tmp';
// Create cache directory
if (!is_dir(__DIR__ . '/cache')) {
mkdir(__DIR__ . '/cache', 0755, true);
}
$hourCount = file_exists($hourFile) ? (int)file_get_contents($hourFile) : 0;
$dayCount = file_exists($dayFile) ? (int)file_get_contents($dayFile) : 0;
if ($hourCount >= MAX_REQUESTS_PER_HOUR || $dayCount >= MAX_REQUESTS_PER_DAY) {
return false;
}
// Increment counters
file_put_contents($hourFile, $hourCount + 1);
file_put_contents($dayFile, $dayCount + 1);
return true;
}
private function sendContactEmail() {
try {
// Create HTML email template
$htmlBody = $this->createEmailTemplate();
// Create plain text version
$textBody = "New Contact Form Submission\n\n";
$textBody .= "Name: {$this->data['name']}\n";
$textBody .= "Email: {$this->data['email']}\n";
$textBody .= "Subject: {$this->data['subject']}\n\n";
$textBody .= "Message:\n{$this->data['message']}\n\n";
$textBody .= "Submitted on: " . date('Y-m-d H:i:s') . "\n";
$textBody .= "IP Address: " . $_SERVER['REMOTE_ADDR'];
$this->gmailService->sendEmail(
TO_EMAIL,
'Contact Form: ' . $this->data['subject'],
$htmlBody,
$textBody
);
return true;
} catch (Exception $e) {
error_log('Failed to send contact email: ' . $e->getMessage());
return false;
}
}
private function createEmailTemplate() {
return "
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: #667eea; color: white; padding: 20px; text-align: center; }
.content { background: #f9f9f9; padding: 20px; }
.field { margin-bottom: 15px; }
.label { font-weight: bold; color: #555; }
.value { margin-top: 5px; }
.footer { background: #333; color: white; padding: 15px; text-align: center; font-size: 12px; }
</style>
</head>
<body>
<div class='container'>
<div class='header'>
<h2>New Contact Form Submission</h2>
</div>
<div class='content'>
<div class='field'>
<div class='label'>Name:</div>
<div class='value'>{$this->data['name']}</div>
</div>
<div class='field'>
<div class='label'>Email:</div>
<div class='value'>{$this->data['email']}</div>
</div>
<div class='field'>
<div class='label'>Subject:</div>
<div class='value'>{$this->data['subject']}</div>
</div>
<div class='field'>
<div class='label'>Message:</div>
<div class='value'>" . nl2br($this->data['message']) . "</div>
</div>
<div class='field'>
<div class='label'>Submitted:</div>
<div class='value'>" . date('Y-m-d H:i:s') . "</div>
</div>
<div class='field'>
<div class='label'>IP Address:</div>
<div class='value'>" . $_SERVER['REMOTE_ADDR'] . "</div>
</div>
</div>
<div class='footer'>
This email was sent from your website contact form.
</div>
</div>
</body>
</html>";
}
private function logSubmission() {
$logData = [
'timestamp' => date('Y-m-d H:i:s'),
'ip' => $_SERVER['REMOTE_ADDR'],
'name' => $this->data['name'],
'email' => $this->data['email'],
'subject' => $this->data['subject'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
];
error_log('Contact form submission: ' . json_encode($logData));
}
private function jsonResponse($success, $message) {
return json_encode([
'success' => $success,
'message' => $message
]);
}
}
// Process the request
$processor = new ContactFormProcessor();
echo $processor->processRequest();
?>Error Handling and Validation
<?php
// callback.php - OAuth callback handler
require_once 'config.php';
require_once 'GmailService.php';
try {
if (!isset($_GET['code'])) {
throw new Exception('Authorization code not received');
}
$gmailService = new GmailService();
$success = $gmailService->handleCallback($_GET['code']);
if ($success) {
$message = "Gmail API authentication successful! Your contact form is now ready to send emails.";
$alertClass = "alert-success";
} else {
$message = "Authentication failed. Please try again.";
$alertClass = "alert-error";
}
} catch (Exception $e) {
$message = "Error: " . $e->getMessage();
$alertClass = "alert-error";
error_log('OAuth callback error: ' . $e->getMessage());
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Authentication Result</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
background: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.alert {
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.btn {
display: inline-block;
padding: 10px 20px;
background: #667eea;
color: white;
text-decoration: none;
border-radius: 5px;
margin-top: 15px;
}
</style>
</head>
<body>
<div class="container">
<h2>Gmail API Authentication</h2>
<div class="alert <?php echo $alertClass; ?>">
<?php echo htmlspecialchars($message); ?>
</div>
<a href="index.html" class="btn">Back to Contact Form</a>
<?php if (isset($success) && $success): ?>
<p><strong>Next Steps:</strong></p>
<ol>
<li>Your contact form is now configured to send emails via Gmail API</li>
<li>Test the contact form to ensure everything works correctly</li>
<li>Monitor the logs for any issues</li>
<li>In production, make sure to use HTTPS and secure your credentials</li>
</ol>
<?php endif; ?>
</div>
</body>
</html>Testing and Deployment
Test Your Contact Form
Follow these steps to test your contact form thoroughly before going live.
Testing Checklist
Functional Testing:
- ✓ Form submits successfully
- ✓ Emails are received
- ✓ Validation works properly
- ✓ Rate limiting prevents spam
- ✓ Error handling works
Security Testing:
- ✓ XSS protection active
- ✓ SQL injection prevention
- ✓ Credentials secured
- ✓ HTTPS enabled (production)
- ✓ Error logs working
Security Best Practices
Essential Security Measures
- • Never store credentials in code - Use environment variables
- • Use HTTPS in production - Encrypt all data transmission
- • Implement rate limiting - Prevent spam and abuse
- • Validate all input - Never trust user data
- • Log security events - Monitor for suspicious activity
- • Keep dependencies updated - Regular security updates
- • Set proper file permissions - Restrict access to sensitive files
Production Environment Setup
Environment Variables (.env file):
GOOGLE_CLIENT_SECRET=your-production-secret
FROM_EMAIL=noreply@yourdomain.com
TO_EMAIL=contact@yourdomain.com
<?php
// production-config.php - Production environment configuration
// Load environment variables
if (file_exists('.env')) {
$lines = file('.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos($line, '=') !== false && strpos($line, '#') !== 0) {
list($key, $value) = explode('=', $line, 2);
$_ENV[trim($key)] = trim($value);
}
}
}
// Production settings
define('ENVIRONMENT', 'production');
define('DEBUG_MODE', false);
// Gmail API Configuration from environment
define('GOOGLE_CLIENT_ID', $_ENV['GOOGLE_CLIENT_ID'] ?? '');
define('GOOGLE_CLIENT_SECRET', $_ENV['GOOGLE_CLIENT_SECRET'] ?? '');
define('GOOGLE_REDIRECT_URI', 'https://yourdomain.com/contact-form/callback.php');
// Email settings
define('FROM_EMAIL', $_ENV['FROM_EMAIL'] ?? '');
define('FROM_NAME', $_ENV['FROM_NAME'] ?? 'Your Website');
define('TO_EMAIL', $_ENV['TO_EMAIL'] ?? '');
// Security settings
define('CSRF_TOKEN_NAME', 'csrf_token');
define('SESSION_NAME', 'secure_contact_session');
// Enhanced rate limiting for production
define('MAX_REQUESTS_PER_HOUR', 3);
define('MAX_REQUESTS_PER_DAY', 10);
// Secure logging
define('LOG_FILE', '/var/log/contact-form/app.log');
define('ERROR_LOG_FILE', '/var/log/contact-form/error.log');
// Production security headers
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: strict-origin-when-cross-origin');
// Secure session settings
ini_set('session.cookie_secure', '1');
ini_set('session.cookie_httponly', '1');
ini_set('session.use_strict_mode', '1');
ini_set('session.cookie_samesite', 'Strict');
// Error reporting
error_reporting(0);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', ERROR_LOG_FILE);
session_name(SESSION_NAME);
session_start();
?>Ready to Build Professional Contact Forms?
Use our development tools to enhance your PHP contact form with beautiful formatting, validation, and optimization features.
Congratulations! What You've Accomplished
Technical Achievements:
- ✅ Professional contact form with Gmail API
- ✅ OAuth 2.0 authentication implementation
- ✅ Comprehensive input validation
- ✅ Rate limiting and spam protection
- ✅ Beautiful HTML email templates
- ✅ Error handling and logging
Security Features:
- ✅ XSS and injection protection
- ✅ Secure credential management
- ✅ HTTPS-ready configuration
- ✅ Production security headers
- ✅ Comprehensive error logging
- ✅ Rate limiting and abuse prevention
You now have a production-ready contact form that leverages Gmail API for reliable email delivery. Your form includes professional validation, security measures, and beautiful email templates that will impress your website visitors and ensure their messages reach you successfully.
