mailer.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. /**
  3. * lib/mailer.php
  4. *
  5. * PHPMailer wrapper. All email sending goes through sendMail().
  6. *
  7. * Requires: vendor/autoload.php (run `composer install`)
  8. * config/mail.php (SMTP constants)
  9. */
  10. use PHPMailer\PHPMailer\PHPMailer;
  11. use PHPMailer\PHPMailer\SMTP;
  12. use PHPMailer\PHPMailer\Exception as MailerException;
  13. require_once __DIR__ . '/../config/mail.php';
  14. /**
  15. * Send an email via SMTP.
  16. *
  17. * @param string $toEmail Recipient address
  18. * @param string $toName Recipient display name
  19. * @param string $subject Email subject
  20. * @param string $htmlBody HTML message body
  21. * @param string|null $textBody Plain-text fallback (auto-stripped from HTML if null)
  22. *
  23. * @return array{success: bool, error: string}
  24. */
  25. function sendMail(string $toEmail, string $toName, string $subject, string $htmlBody, ?string $textBody = null): array
  26. {
  27. $mail = new PHPMailer(true);
  28. try {
  29. $mail->isSMTP();
  30. $mail->Host = MAIL_HOST;
  31. $mail->SMTPAuth = true;
  32. $mail->Username = MAIL_USERNAME;
  33. $mail->Password = MAIL_PASSWORD;
  34. $mail->SMTPSecure = MAIL_ENCRYPTION === 'ssl' ? PHPMailer::ENCRYPTION_SMTPS : PHPMailer::ENCRYPTION_STARTTLS;
  35. $mail->Port = MAIL_PORT;
  36. $mail->CharSet = 'UTF-8';
  37. $mail->setFrom(MAIL_FROM, MAIL_FROM_NAME);
  38. $mail->addAddress($toEmail, $toName);
  39. $mail->isHTML(true);
  40. $mail->Subject = $subject;
  41. $mail->Body = $htmlBody;
  42. $mail->AltBody = $textBody ?? strip_tags($htmlBody);
  43. $mail->send();
  44. return ['success' => true, 'error' => ''];
  45. } catch (MailerException $e) {
  46. error_log('Mailer error to ' . $toEmail . ': ' . $mail->ErrorInfo);
  47. return ['success' => false, 'error' => $mail->ErrorInfo];
  48. }
  49. }
  50. /**
  51. * Send a password reset email.
  52. */
  53. function sendPasswordResetEmail(string $email, string $token): bool
  54. {
  55. $resetUrl = 'https://cropmonitor.com.au/login/reset-password.php?token=' . urlencode($token);
  56. $html = '
  57. <!DOCTYPE html>
  58. <html>
  59. <body style="font-family:Arial,sans-serif;background:#f4f4f4;padding:20px;">
  60. <div style="max-width:560px;margin:0 auto;background:#fff;border-radius:6px;padding:32px;">
  61. <h2 style="color:#2d6a2d;">Crop Monitor — Password Reset</h2>
  62. <p>We received a request to reset your password. Click the button below to choose a new one.</p>
  63. <p style="margin:28px 0;text-align:center;">
  64. <a href="' . htmlspecialchars($resetUrl, ENT_QUOTES, 'UTF-8') . '"
  65. style="background:#2d6a2d;color:#fff;padding:12px 28px;border-radius:4px;text-decoration:none;font-size:15px;">
  66. Reset My Password
  67. </a>
  68. </p>
  69. <p style="color:#666;font-size:13px;">This link expires in <strong>1 hour</strong>. If you did not request a password reset, you can safely ignore this email.</p>
  70. <hr style="border:none;border-top:1px solid #eee;margin:24px 0;">
  71. <p style="color:#999;font-size:12px;">Crop Monitor &mdash; Australian Crop Management Platform</p>
  72. </div>
  73. </body>
  74. </html>';
  75. $text = "Crop Monitor — Password Reset\n\n"
  76. . "Click the link below to reset your password (expires in 1 hour):\n\n"
  77. . $resetUrl . "\n\n"
  78. . "If you did not request this, ignore this email.";
  79. $result = sendMail($email, $email, 'Reset your Crop Monitor password', $html, $text);
  80. return $result['success'];
  81. }
  82. /**
  83. * Send a welcome email after registration.
  84. */
  85. function sendWelcomeEmail(string $email, string $fullname): bool
  86. {
  87. $loginUrl = 'https://cropmonitor.com.au/login/login.php';
  88. $html = '
  89. <!DOCTYPE html>
  90. <html>
  91. <body style="font-family:Arial,sans-serif;background:#f4f4f4;padding:20px;">
  92. <div style="max-width:560px;margin:0 auto;background:#fff;border-radius:6px;padding:32px;">
  93. <h2 style="color:#2d6a2d;">Welcome to Crop Monitor!</h2>
  94. <p>Hi ' . htmlspecialchars($fullname, ENT_QUOTES, 'UTF-8') . ',</p>
  95. <p>Your account has been created. You can now log in and start managing your crop analysis records.</p>
  96. <p style="margin:28px 0;text-align:center;">
  97. <a href="' . htmlspecialchars($loginUrl, ENT_QUOTES, 'UTF-8') . '"
  98. style="background:#2d6a2d;color:#fff;padding:12px 28px;border-radius:4px;text-decoration:none;font-size:15px;">
  99. Go to Crop Monitor
  100. </a>
  101. </p>
  102. <p style="color:#666;font-size:13px;">If you have any questions, reply to this email and we will get back to you.</p>
  103. <hr style="border:none;border-top:1px solid #eee;margin:24px 0;">
  104. <p style="color:#999;font-size:12px;">Crop Monitor &mdash; Australian Crop Management Platform</p>
  105. </div>
  106. </body>
  107. </html>';
  108. $text = "Welcome to Crop Monitor, {$fullname}!\n\n"
  109. . "Your account has been created. Log in here:\n\n"
  110. . $loginUrl . "\n\n"
  111. . "If you have any questions, reply to this email.";
  112. $result = sendMail($email, $fullname, 'Welcome to Crop Monitor', $html, $text);
  113. return $result['success'];
  114. }