apiKey = getSetting('sendgrid_api_key', 'YOUR_SENDGRID_API_KEY_HERE'); $this->fromEmail = getSetting('sendgrid_from_email', 'noreply@tomsjavajive.com'); $this->fromName = getSetting('sendgrid_from_name', "Tom's Java Jive"); } /** * Send email via SendGrid API */ public function send(string $to, string $subject, string $htmlContent, ?string $textContent = null): array { $data = [ 'personalizations' => [ [ 'to' => [['email' => $to]], 'subject' => $subject ] ], 'from' => [ 'email' => $this->fromEmail, 'name' => $this->fromName ], 'content' => [] ]; if ($textContent) { $data['content'][] = ['type' => 'text/plain', 'value' => $textContent]; } $data['content'][] = ['type' => 'text/html', 'value' => $htmlContent]; $ch = curl_init('https://api.sendgrid.com/v3/mail/send'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $this->apiKey, 'Content-Type: application/json' ], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30 ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { return ['success' => false, 'error' => $error]; } // SendGrid returns 202 for accepted if ($httpCode >= 200 && $httpCode < 300) { return ['success' => true]; } return ['success' => false, 'error' => $response, 'code' => $httpCode]; } /** * Send order confirmation email */ public function sendOrderConfirmation(array $order): array { $items = json_decode($order['items'], true); $itemsHtml = ''; foreach ($items as $item) { $itemsHtml .= sprintf( '%s %d %s', htmlspecialchars($item['name']), $item['quantity'], formatCurrency($item['total']) ); } $html = $this->getTemplate('order_confirmation', [ 'order_number' => $order['order_number'], 'customer_name' => $order['customer_name'] ?? 'Valued Customer', 'items_html' => $itemsHtml, 'subtotal' => formatCurrency($order['subtotal']), 'tax' => formatCurrency($order['tax']), 'discount' => $order['discount'] > 0 ? '-' . formatCurrency($order['discount']) : '$0.00', 'total' => formatCurrency($order['total']), 'payment_method' => ucfirst($order['payment_method'] ?? 'N/A'), 'order_date' => date('F j, Y', strtotime($order['created_at'])) ]); return $this->send( $order['customer_email'], "Order Confirmation - #{$order['order_number']}", $html ); } /** * Send shipping notification email */ public function sendShippingNotification(array $order): array { $html = $this->getTemplate('shipping_notification', [ 'order_number' => $order['order_number'], 'customer_name' => $order['customer_name'] ?? 'Valued Customer', 'tracking_number' => $order['tracking_number'], 'tracking_url' => $order['tracking_url'] ?? '#', 'carrier' => $order['shipping_carrier'] ?? 'Our shipping partner' ]); return $this->send( $order['customer_email'], "Your Order Has Shipped - #{$order['order_number']}", $html ); } /** * Send password reset email */ public function sendPasswordReset(string $email, string $resetToken, string $name = ''): array { $resetUrl = SITE_URL . '/reset-password.php?token=' . $resetToken; $html = $this->getTemplate('password_reset', [ 'customer_name' => $name ?: 'there', 'reset_url' => $resetUrl, 'expires' => '1 hour' ]); return $this->send( $email, "Reset Your Password - Tom's Java Jive", $html ); } /** * Send welcome email to new customer */ public function sendWelcome(string $email, string $name = ''): array { $html = $this->getTemplate('welcome', [ 'customer_name' => $name ?: 'Coffee Lover', 'shop_url' => SITE_URL . '/shop.php' ]); return $this->send( $email, "Welcome to Tom's Java Jive!", $html ); } /** * Send abandoned cart reminder */ public function sendAbandonedCartReminder(array $cart): array { $items = json_decode($cart['items'], true); $itemsHtml = ''; foreach ($items as $item) { $itemsHtml .= sprintf( '
%s - %s
', htmlspecialchars($item['name']), formatCurrency($item['price']) ); } $html = $this->getTemplate('abandoned_cart', [ 'items_html' => $itemsHtml, 'total' => formatCurrency($cart['subtotal']), 'cart_url' => SITE_URL . '/cart.php' ]); return $this->send( $cart['customer_email'], "You left something behind!", $html ); } /** * Get email template with variables replaced */ private function getTemplate(string $name, array $vars = []): string { $templates = [ 'order_confirmation' => '

Order Confirmed!

Hi {{customer_name}},

Thank you for your order! We\'ve received it and will begin processing right away.

Order #{{order_number}}

{{order_date}}

{{items_html}}
Item Qty Price

Subtotal: {{subtotal}}

Tax: {{tax}}

Discount: {{discount}}

Total: {{total}}

Payment Method: {{payment_method}}

If you have any questions, reply to this email or visit our website.

© ' . date('Y') . ' Tom\'s Java Jive. All rights reserved.

', 'shipping_notification' => '

Your Order Has Shipped!

Hi {{customer_name}},

Great news! Your order #{{order_number}} is on its way to you.

Tracking Number

{{tracking_number}}

Carrier: {{carrier}}

Track Your Package

Please allow 24-48 hours for tracking information to update.

© ' . date('Y') . ' Tom\'s Java Jive. All rights reserved.

', 'password_reset' => '

Reset Your Password

Hi {{customer_name}},

We received a request to reset your password. Click the button below to create a new password:

Reset Password

This link will expire in {{expires}}. If you didn\'t request this, you can safely ignore this email.

© ' . date('Y') . ' Tom\'s Java Jive. All rights reserved.

', 'welcome' => '

Welcome to the Family!

Hi {{customer_name}},

Welcome to Tom\'s Java Jive! We\'re thrilled to have you join our community of coffee lovers.

Here\'s what you can look forward to:

Start Shopping

Cheers,
The Tom\'s Java Jive Team

© ' . date('Y') . ' Tom\'s Java Jive. All rights reserved.

', 'abandoned_cart' => '

Forget Something?

Hey there!

We noticed you left some amazing items in your cart. Don\'t let them get away!

{{items_html}}
Total: {{total}}
Complete Your Order

Need help? Just reply to this email and we\'ll assist you!

© ' . date('Y') . ' Tom\'s Java Jive. All rights reserved.

' ]; $template = $templates[$name] ?? '

Email template not found.

'; foreach ($vars as $key => $value) { $template = str_replace('{{' . $key . '}}', $value, $template); } return $template; } } // Helper function for easy access function sendEmail(): SendGridEmail { static $instance = null; if ($instance === null) { $instance = new SendGridEmail(); } return $instance; }