File "send_message.php"
Full path: /home2/santhos2/public_html/bharath-coe.firstmatrix.in.net/api/batches/send_message.php
File size: 19.87 KiB (20346 bytes)
MIME-type: text/x-php
Charset: utf-8
<?php
// Don't include config.php here as it's already included by the calling file
class EmailSender {
private $pdo;
private $settings;
public function __construct($pdo) {
$this->pdo = $pdo;
$this->loadSettings();
}
private function loadSettings() {
$stmt = $this->pdo->prepare("SELECT setting_name, setting_value FROM smtp_settings WHERE is_active = 1");
$stmt->execute();
$this->settings = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$this->settings[$row['setting_name']] = $row['setting_value'];
}
}
public function sendMessage($to_email, $subject, $message, $template_id = null, $booking_id = null, $from_name_override = null) {
try {
// Debug logging
error_log("Email sendMessage called with: to_email=$to_email, subject_length=" . strlen($subject));
// Validate inputs
if (empty($to_email)) {
throw new Exception('Email address is required');
}
if (empty($subject)) {
throw new Exception('Subject is required');
}
if (empty($message)) {
throw new Exception('Message is required');
}
// Validate email format
if (!filter_var($to_email, FILTER_VALIDATE_EMAIL)) {
throw new Exception('Invalid email address format');
}
// Validate settings
if (empty($this->settings['smtp_host'])) {
throw new Exception('SMTP Host not configured');
}
if (empty($this->settings['smtp_username'])) {
throw new Exception('SMTP Username not configured');
}
if (empty($this->settings['smtp_password'])) {
throw new Exception('SMTP Password not configured');
}
// Log message before sending
$log_id = $this->logMessage($to_email, $subject, $message, $template_id, $booking_id);
// Send message via SMTP
$smtp_response = $this->sendEmailViaSMTP($to_email, $subject, $message, $from_name_override);
// Update log with response
$this->updateMessageLog($log_id, $smtp_response);
return [
'status' => 'success',
'message' => 'Email sent successfully',
'log_id' => $log_id,
'smtp_response' => $smtp_response
];
} catch (Exception $e) {
error_log("Email sendMessage error: " . $e->getMessage());
// Log error
if (isset($log_id)) {
$this->updateMessageLog($log_id, null, 'failed', $e->getMessage());
}
return [
'status' => 'error',
'message' => $e->getMessage()
];
}
}
private function sendEmailViaSMTP($to_email, $subject, $message, $from_name_override = null) {
// Get SMTP settings
$smtp_host = $this->settings['smtp_host'] ?? '';
$smtp_port = (int)($this->settings['smtp_port'] ?? 587);
$smtp_username = $this->settings['smtp_username'] ?? '';
$smtp_password = $this->settings['smtp_password'] ?? '';
$smtp_encryption = $this->settings['smtp_encryption'] ?? 'tls';
$from_email = $this->settings['from_email'] ?? $smtp_username;
$from_name = $from_name_override ?: ($this->settings['from_name'] ?? 'Controller Of Examination');
// Validate required settings
if (empty($smtp_host) || empty($smtp_username) || empty($smtp_password)) {
throw new Exception('SMTP configuration incomplete');
}
// Create email content
$email_content = $this->createEmailContent($message, $from_name_override);
// Send email using proper SMTP connection
$smtp_response = $this->sendEmailWithSMTP($smtp_host, $smtp_port, $smtp_username, $smtp_password, $smtp_encryption, $from_email, $from_name, $to_email, $subject, $email_content);
return [
'smtp_host' => $smtp_host,
'smtp_port' => $smtp_port,
'smtp_username' => $smtp_username,
'from_email' => $from_email,
'to_email' => $to_email,
'subject' => $subject,
'response' => $smtp_response
];
}
private function sendEmailWithSMTP($host, $port, $username, $password, $encryption, $from, $from_name, $to, $subject, $message) {
// Use PHPMailer if available, otherwise use a simple SMTP implementation
if (class_exists('PHPMailer\PHPMailer\PHPMailer')) {
error_log("Using PHPMailer for email sending");
return $this->sendWithPHPMailer($host, $port, $username, $password, $encryption, $from, $from_name, $to, $subject, $message);
} else {
error_log("PHPMailer not available, using simple SMTP implementation");
return $this->sendWithSimpleSMTP($host, $port, $username, $password, $encryption, $from, $from_name, $to, $subject, $message);
}
}
private function sendWithPHPMailer($host, $port, $username, $password, $encryption, $from, $from_name, $to, $subject, $message) {
try {
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
// Server settings
$mail->isSMTP();
$mail->Host = $host;
$mail->SMTPAuth = true;
$mail->Username = $username;
$mail->Password = $password;
$mail->SMTPSecure = $encryption;
$mail->Port = $port;
$mail->SMTPDebug = 0; // Set to 2 for debugging
$mail->Timeout = 30; // 30 seconds timeout
// Additional settings for better compatibility
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
// Recipients
$mail->setFrom($from, $from_name);
$mail->addAddress($to);
// Content
$mail->isHTML(true);
$mail->Subject = $subject;
$mail->Body = $message;
$mail->CharSet = 'UTF-8';
error_log("PHPMailer: Attempting to send email to $to via $host:$port");
$mail->send();
error_log("PHPMailer: Email sent successfully to $to");
return 'Email sent successfully via PHPMailer';
} catch (Exception $e) {
error_log("PHPMailer Error: " . $e->getMessage());
throw new Exception('PHPMailer Error: ' . $e->getMessage());
}
}
private function sendWithSimpleSMTP($host, $port, $username, $password, $encryption, $from, $from_name, $to, $subject, $message) {
// Create a simple SMTP connection using fsockopen
$timeout = 30;
$errno = 0;
$errstr = '';
// Connect to SMTP server
$connection = @fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$connection) {
throw new Exception("Failed to connect to SMTP server: $errstr (Error $errno)");
}
try {
// Read server greeting
$response = fgets($connection, 515);
if (!$response || !preg_match('/^220/', $response)) {
throw new Exception("SMTP server not ready: " . trim($response));
}
// Send EHLO
fputs($connection, "EHLO " . $_SERVER['HTTP_HOST'] . "\r\n");
$response = fgets($connection, 515);
// Start TLS if required
if (strtolower($encryption) === 'tls') {
fputs($connection, "STARTTLS\r\n");
$response = fgets($connection, 515);
if (!preg_match('/^220/', $response)) {
throw new Exception("STARTTLS failed: " . trim($response));
}
// Enable crypto
if (!stream_socket_enable_crypto($connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
throw new Exception("TLS negotiation failed");
}
// Send EHLO again after TLS
fputs($connection, "EHLO " . $_SERVER['HTTP_HOST'] . "\r\n");
$response = fgets($connection, 515);
}
// Authenticate
fputs($connection, "AUTH LOGIN\r\n");
$response = fgets($connection, 515);
if (!preg_match('/^334/', $response)) {
throw new Exception("AUTH LOGIN not supported: " . trim($response));
}
fputs($connection, base64_encode($username) . "\r\n");
$response = fgets($connection, 515);
if (!preg_match('/^334/', $response)) {
throw new Exception("Username rejected: " . trim($response));
}
fputs($connection, base64_encode($password) . "\r\n");
$response = fgets($connection, 515);
if (!preg_match('/^235/', $response)) {
throw new Exception("Authentication failed: " . trim($response));
}
// Send MAIL FROM
fputs($connection, "MAIL FROM: <$from>\r\n");
$response = fgets($connection, 515);
if (!preg_match('/^250/', $response)) {
throw new Exception("MAIL FROM failed: " . trim($response));
}
// Send RCPT TO
fputs($connection, "RCPT TO: <$to>\r\n");
$response = fgets($connection, 515);
if (!preg_match('/^250/', $response)) {
throw new Exception("RCPT TO failed: " . trim($response));
}
// Send DATA
fputs($connection, "DATA\r\n");
$response = fgets($connection, 515);
if (!preg_match('/^354/', $response)) {
throw new Exception("DATA command failed: " . trim($response));
}
// Prepare email headers
$headers = [
"From: $from_name <$from>",
"To: $to",
"Subject: $subject",
"MIME-Version: 1.0",
"Content-Type: text/html; charset=UTF-8",
"X-Mailer: PHP/" . phpversion()
];
$email_data = implode("\r\n", $headers) . "\r\n\r\n" . $message . "\r\n.\r\n";
// Send email data
fputs($connection, $email_data);
$response = fgets($connection, 515);
if (!preg_match('/^250/', $response)) {
throw new Exception("Email sending failed: " . trim($response));
}
// Quit
fputs($connection, "QUIT\r\n");
fclose($connection);
return 'Email sent successfully via SMTP';
} catch (Exception $e) {
if ($connection) {
fclose($connection);
}
throw $e;
}
}
private function createEmailContent($message, $brand_override = null) {
// Use configured name as heading; fall back to a sensible default
$brand = $brand_override ?: ($this->settings['from_name'] ?? 'Controller Of Examination');
// Treat $message as HTML (callers often pass HTML with links); do not escape
$bodyHtml = (string)$message;
$html = '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>' . htmlspecialchars($brand) . '</title>
<style>
@media screen { body { background:#f3f4f6; margin:0; padding:0; } }
.wrapper{width:100%; background:#f3f4f6; padding:20px 0;}
.container{max-width:640px; margin:0 auto; background:#ffffff; border-radius:8px; overflow:hidden; box-shadow:0 2px 8px rgba(0,0,0,0.06);}
.header{background:#0d6efd; color:#ffffff; padding:18px 22px; text-align:center;}
.brand{margin:0; font-size:18px; letter-spacing:.3px;}
.sub{margin:2px 0 0; font-size:12px; opacity:.9;}
.content{padding:22px; color:#111827; font-family:Arial,Helvetica,sans-serif; line-height:1.6;}
.content a{color:#0d6efd; text-decoration:none;}
.card{border:1px solid #e5e7eb; border-radius:8px; padding:14px 16px; background:#fafafa;}
.btn{display:inline-block; background:#0d6efd; color:#ffffff !important; padding:10px 16px; border-radius:6px; text-decoration:none; margin:8px 0;}
.footer{padding:14px 22px; text-align:center; color:#6b7280; font-size:12px;}
</style>
</head>
<body>
<div class="wrapper">
<div class="container">
<div class="header">
<h1 class="brand">' . htmlspecialchars($brand) . '</h1>
<div class="sub">Official Communication</div>
</div>
<div class="content">'
. $bodyHtml .
'</div>
<div class="footer">
<div>This is an automated email. Please do not reply.</div>
</div>
</div>
</div>
</body>
</html>';
return $html;
}
private function logMessage($to_email, $subject, $message, $template_id = null, $booking_id = null) {
$stmt = $this->pdo->prepare("INSERT INTO email_message_logs (booking_id, template_id, to_email, subject, message_content, status, created_by) VALUES (?, ?, ?, ?, ?, 'pending', ?)");
$stmt->execute([$booking_id, $template_id, $to_email, $subject, $message, $_SESSION['user_id'] ?? null]);
return $this->pdo->lastInsertId();
}
private function updateMessageLog($log_id, $smtp_response = null, $status = 'sent', $error_message = null) {
$stmt = $this->pdo->prepare("UPDATE email_message_logs SET smtp_response = ?, status = ?, error_message = ?, delivered_at = ? WHERE id = ?");
$delivered_at = ($status === 'delivered') ? date('Y-m-d H:i:s') : null;
$stmt->execute([json_encode($smtp_response), $status, $error_message, $delivered_at, $log_id]);
}
public function sendBookingEmail($booking_id, $template_type = 'booking_created') {
try {
error_log("Email sendBookingEmail called with: booking_id=$booking_id, template_type=$template_type");
// Get booking details
$stmt = $this->pdo->prepare("SELECT * FROM booking WHERE id = ?");
$stmt->execute([$booking_id]);
$booking = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$booking) {
throw new Exception('Booking not found');
}
error_log("Booking found: consignee_email=" . ($booking['consignee_email'] ?? 'N/A'));
// Get template
$stmt = $this->pdo->prepare("SELECT * FROM email_message_templates WHERE template_type = ? AND is_active = 1 ORDER BY id ASC LIMIT 1");
$stmt->execute([$template_type]);
$template = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$template) {
throw new Exception("No active template found for type: $template_type");
}
error_log("Template found: " . $template['template_name']);
// Prepare message variables
$variables = $this->prepareBookingVariables($booking);
error_log("Variables prepared: " . json_encode($variables));
// Replace variables in template
$subject = $this->replaceTemplateVariables($template['subject_template'], $variables);
$message = $this->replaceTemplateVariables($template['message_template'], $variables);
error_log("Message prepared: " . substr($message, 0, 100) . "...");
// Get recipient email (use consignee email if available, otherwise use a default)
$to_email = $booking['consignee_email'] ?? $this->settings['from_email'] ?? 'admin@example.com';
// Validate email address
if (empty($to_email) || !filter_var($to_email, FILTER_VALIDATE_EMAIL)) {
throw new Exception('Invalid or missing consignee email address. Please provide a valid email address.');
}
error_log("Sending email to: $to_email");
// Send email
return $this->sendMessage($to_email, $subject, $message, $template['id'], $booking_id);
} catch (Exception $e) {
error_log("Email sendBookingEmail error: " . $e->getMessage());
return [
'status' => 'error',
'message' => $e->getMessage()
];
}
}
private function prepareBookingVariables($booking) {
return [
'consignee_name' => $booking['consignee_name'],
'cn_number' => $booking['cn_number'],
'consignor_name' => $booking['consignor_name'],
'content' => $booking['content'] ?? 'N/A',
'total_amount' => number_format($booking['total_amount'], 2),
'booking_date' => $booking['booking_date'],
'tracking_url' => $this->generateTrackingUrl($booking['cn_number']),
'status' => $booking['status'] == 1 ? 'Active' : 'Inactive',
'cancellation_reason' => 'N/A', // This would be set when cancelling
'company_name' => $this->settings['from_name'] ?? 'Booking System'
];
}
private function replaceTemplateVariables($template, $variables) {
foreach ($variables as $key => $value) {
$template = str_replace('{' . $key . '}', $value, $template);
}
return $template;
}
private function generateTrackingUrl($cn_number) {
$base_url = $_SERVER['HTTP_HOST'] ?? 'localhost';
return "https://$base_url/track.php?cn=$cn_number";
}
}
// Handle API requests only if this file is called directly
if ($_SERVER['REQUEST_METHOD'] === 'POST' && basename($_SERVER['SCRIPT_NAME']) === 'send_message.php') {
try {
$action = $_POST['action'] ?? '';
if ($action === 'resend') {
// Handle resend functionality
$log_id = $_POST['log_id'] ?? '';
if (empty($log_id)) {
throw new Exception('Log ID is required for resend');
}
// Get the original message log
$stmt = $pdo->prepare("SELECT * FROM email_message_logs WHERE id = ?");
$stmt->execute([$log_id]);
$log = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$log) {
throw new Exception('Message log not found');
}
$email = new EmailSender($pdo);
$result = $email->sendMessage($log['to_email'], $log['subject'], $log['message_content'], $log['template_id'], $log['booking_id']);
echo json_encode($result);
} else {
// Handle normal message sending
$to_email = $_POST['to_email'] ?? '';
$subject = $_POST['subject'] ?? '';
$message = $_POST['message'] ?? '';
$template_id = $_POST['template_id'] ?? null;
$booking_id = $_POST['booking_id'] ?? null;
if (empty($to_email) || empty($subject) || empty($message)) {
throw new Exception('Email address, subject, and message are required');
}
$email = new EmailSender($pdo);
$result = $email->sendMessage($to_email, $subject, $message, $template_id, $booking_id);
echo json_encode($result);
}
} catch (Exception $e) {
echo json_encode([
'status' => 'error',
'message' => $e->getMessage()
]);
}
}
?>