- **Migrasi ke PHPMailer:** - Mengganti penggunaan `Illuminate\Support\Facades\Mail` ke PHPMailer untuk pengiriman email. - Menambahkan service baru `PHPMailerService` dengan dukungan autentikasi NTLM/GSSAPI. - Mengintegrasikan logika pengiriman email ke dalam `StatementEmail` menggunakan PHPMailer. - Memindahkan logika attachment dan body email ke helper method pada kelas `StatementEmail`. - **Perbaikan Logging dan Penanganan Error:** - Menambah logging lebih mendetail pada proses pengiriman email, termasuk informasi seperti penerima, subjek, dan status pengiriman. - Menambahkan fallback untuk pembuatan konten HTML jika terjadi kegagalan rendering pada template Blade. - Menambahkan pengecekan dan logging untuk kegagalan pengiriman email dengan mekanisme exception handling. - **Peningkatan Template Email:** - Memperbaiki elemen ulasan pada template email untuk mendukung tampilan yang lebih bersih menggunakan `list-style-type: none`. - Memodifikasi markup footer untuk memberikan batas terformat lebih baik. - **Optimasi Proses Backend:** - Menambahkan delay antar pengiriman email untuk menghindari rate limiting pada koneksi NTLM/GSSAPI. - Menyediakan format nama attachment dinamis berdasarkan rekening dan periode laporan. - Memanfaatkan konfigurasi enkripsi dinamis, dengan fallback untuk pengujian/development. Signed-off-by: Daeng Deni Mardaeni <ddeni05@gmail.com>
290 lines
10 KiB
PHP
290 lines
10 KiB
PHP
<?php
|
|
|
|
namespace Modules\Webstatement\Services;
|
|
|
|
use PHPMailer\PHPMailer\PHPMailer;
|
|
use PHPMailer\PHPMailer\SMTP;
|
|
use PHPMailer\PHPMailer\Exception;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Config;
|
|
|
|
/**
|
|
* Service untuk menangani pengiriman email menggunakan PHPMailer
|
|
* dengan dukungan autentikasi NTLM dan GSSAPI
|
|
*/
|
|
class PHPMailerService
|
|
{
|
|
protected $mailer;
|
|
|
|
/**
|
|
* Inisialisasi PHPMailer dengan konfigurasi NTLM/GSSAPI
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->mailer = new PHPMailer(true);
|
|
$this->configureSMTP();
|
|
|
|
Log::info('PHPMailerService initialized with NTLM/GSSAPI support');
|
|
}
|
|
|
|
/**
|
|
* Konfigurasi SMTP dengan dukungan NTLM/GSSAPI dan fallback untuk development
|
|
*/
|
|
protected function configureSMTP(): void
|
|
{
|
|
try {
|
|
// Server settings
|
|
$this->mailer->isSMTP();
|
|
$this->mailer->Host = config('mail.mailers.phpmailer.host', env('MAIL_HOST'));
|
|
$this->mailer->Port = config('mail.mailers.phpmailer.port', env('MAIL_PORT', 587));
|
|
|
|
// Deteksi apakah perlu autentikasi berdasarkan username
|
|
$username = config('mail.mailers.phpmailer.username', env('MAIL_USERNAME'));
|
|
$password = config('mail.mailers.phpmailer.password', env('MAIL_PASSWORD'));
|
|
|
|
// Hanya aktifkan autentikasi jika username dan password tersedia
|
|
if (!empty($username) && $username !== 'null' && !empty($password) && $password !== 'null') {
|
|
$this->mailer->SMTPAuth = true;
|
|
$this->mailer->Username = $username;
|
|
$this->mailer->Password = $password;
|
|
|
|
Log::info('SMTP authentication enabled', [
|
|
'username' => $username,
|
|
'host' => $this->mailer->Host
|
|
]);
|
|
|
|
// Dukungan NTLM/GSSAPI untuk production
|
|
$authType = config('mail.mailers.phpmailer.auth_type', env('MAIL_AUTH_TYPE', 'NTLM'));
|
|
|
|
if (strtoupper($authType) === 'NTLM') {
|
|
$this->mailer->AuthType = 'NTLM';
|
|
$this->mailer->Realm = config('mail.mailers.phpmailer.realm', env('MAIL_REALM', ''));
|
|
$this->mailer->Workstation = config('mail.mailers.phpmailer.workstation', env('MAIL_WORKSTATION', ''));
|
|
|
|
Log::info('NTLM authentication configured', [
|
|
'realm' => $this->mailer->Realm,
|
|
'workstation' => $this->mailer->Workstation
|
|
]);
|
|
} elseif (strtoupper($authType) === 'GSSAPI') {
|
|
$this->mailer->AuthType = 'XOAUTH2';
|
|
Log::info('GSSAPI authentication configured');
|
|
}
|
|
} else {
|
|
// Untuk development server seperti Mailpit
|
|
$this->mailer->SMTPAuth = false;
|
|
|
|
Log::info('SMTP authentication disabled for development', [
|
|
'host' => $this->mailer->Host,
|
|
'port' => $this->mailer->Port
|
|
]);
|
|
}
|
|
|
|
// Encryption configuration
|
|
$encryption = config('mail.mailers.phpmailer.encryption', env('MAIL_ENCRYPTION'));
|
|
$port = $this->mailer->Port;
|
|
|
|
if (!empty($encryption) && $encryption !== 'null') {
|
|
if ($encryption === 'tls' && ($port == 587 || $port == 25)) {
|
|
$this->mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
|
Log::info('Using STARTTLS encryption', ['port' => $port]);
|
|
} elseif ($encryption === 'ssl' && ($port == 465 || $port == 993)) {
|
|
$this->mailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
|
|
Log::info('Using SSL encryption', ['port' => $port]);
|
|
}
|
|
} else {
|
|
// Untuk development/testing server
|
|
$this->mailer->SMTPSecure = false;
|
|
$this->mailer->SMTPAutoTLS = false;
|
|
Log::info('Using no encryption (plain text)', ['port' => $port]);
|
|
}
|
|
|
|
// Tambahan konfigurasi untuk kompatibilitas
|
|
$this->mailer->SMTPOptions = array(
|
|
'ssl' => array(
|
|
'verify_peer' => false,
|
|
'verify_peer_name' => false,
|
|
'allow_self_signed' => true
|
|
)
|
|
);
|
|
|
|
// Debug mode - COMMENTED OUT
|
|
// if (config('app.debug')) {
|
|
// $this->mailer->SMTPDebug = SMTP::DEBUG_SERVER;
|
|
// }
|
|
|
|
// Timeout settings
|
|
$this->mailer->Timeout = config('mail.mailers.phpmailer.timeout', 30);
|
|
$this->mailer->SMTPKeepAlive = true;
|
|
|
|
Log::info('SMTP configured successfully', [
|
|
'host' => $this->mailer->Host,
|
|
'port' => $this->mailer->Port,
|
|
'auth_enabled' => $this->mailer->SMTPAuth,
|
|
'encryption' => $encryption ?: 'none',
|
|
'smtp_secure' => $this->mailer->SMTPSecure ?: 'none'
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
Log::error('Failed to configure SMTP', [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Kirim email dengan attachment
|
|
*
|
|
* @param string $to Email tujuan
|
|
* @param string $subject Subjek email
|
|
* @param string $body Body email (HTML)
|
|
* @param string|null $attachmentPath Path file attachment
|
|
* @param string|null $attachmentName Nama file attachment
|
|
* @param string|null $mimeType MIME type attachment
|
|
* @return bool
|
|
*/
|
|
/**
|
|
* Kirim email dengan handling khusus untuk development dan production
|
|
*
|
|
* @param string $to Email tujuan
|
|
* @param string $subject Subjek email
|
|
* @param string $body Body email (HTML)
|
|
* @param string|null $attachmentPath Path file attachment
|
|
* @param string|null $attachmentName Nama file attachment
|
|
* @param string|null $mimeType MIME type attachment
|
|
* @return bool
|
|
*/
|
|
public function sendEmail(
|
|
string $to,
|
|
string $subject,
|
|
string $body,
|
|
?string $attachmentPath = null,
|
|
?string $attachmentName = null,
|
|
?string $mimeType = 'application/pdf'
|
|
): bool {
|
|
try {
|
|
// Reset recipients dan attachments
|
|
$this->mailer->clearAddresses();
|
|
$this->mailer->clearAttachments();
|
|
|
|
// Set sender
|
|
$fromAddress = config('mail.from.address', env('MAIL_FROM_ADDRESS'));
|
|
$fromName = config('mail.from.name', env('MAIL_FROM_NAME'));
|
|
|
|
if (!empty($fromAddress)) {
|
|
$this->mailer->setFrom($fromAddress, $fromName);
|
|
} else {
|
|
// Fallback untuk development
|
|
$this->mailer->setFrom('noreply@localhost', 'Development Server');
|
|
}
|
|
|
|
// Add recipient
|
|
$this->mailer->addAddress($to);
|
|
|
|
// Content
|
|
$this->mailer->isHTML(true);
|
|
$this->mailer->Subject = $subject;
|
|
$this->mailer->Body = $body;
|
|
$this->mailer->AltBody = strip_tags($body);
|
|
|
|
// Attachment
|
|
if ($attachmentPath && file_exists($attachmentPath)) {
|
|
$this->mailer->addAttachment(
|
|
$attachmentPath,
|
|
$attachmentName ?: basename($attachmentPath),
|
|
'base64',
|
|
$mimeType
|
|
);
|
|
|
|
Log::info('Attachment added to email', [
|
|
'path' => $attachmentPath,
|
|
'name' => $attachmentName,
|
|
'mime_type' => $mimeType,
|
|
'file_size' => filesize($attachmentPath)
|
|
]);
|
|
}
|
|
|
|
// Attempt to send
|
|
$result = $this->mailer->send();
|
|
|
|
Log::info('Email sent successfully via PHPMailer', [
|
|
'to' => $to,
|
|
'subject' => $subject,
|
|
'has_attachment' => !is_null($attachmentPath),
|
|
'host' => $this->mailer->Host,
|
|
'port' => $this->mailer->Port,
|
|
'auth_enabled' => $this->mailer->SMTPAuth
|
|
]);
|
|
|
|
return $result;
|
|
|
|
} catch (Exception $e) {
|
|
Log::error('Failed to send email via PHPMailer', [
|
|
'to' => $to,
|
|
'subject' => $subject,
|
|
'host' => $this->mailer->Host,
|
|
'port' => $this->mailer->Port,
|
|
'auth_enabled' => $this->mailer->SMTPAuth,
|
|
'error' => $e->getMessage(),
|
|
'error_code' => $e->getCode(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test koneksi SMTP dengan fallback encryption
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function testConnection(): bool
|
|
{
|
|
try {
|
|
// Coba koneksi dengan konfigurasi saat ini
|
|
$this->mailer->smtpConnect();
|
|
$this->mailer->smtpClose();
|
|
|
|
Log::info('SMTP connection test successful with current config');
|
|
return true;
|
|
|
|
} catch (Exception $e) {
|
|
Log::warning('SMTP connection failed, trying fallback', [
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
// Fallback: coba tanpa encryption
|
|
try {
|
|
$this->mailer->SMTPSecure = false;
|
|
$this->mailer->SMTPAutoTLS = false;
|
|
|
|
$this->mailer->smtpConnect();
|
|
$this->mailer->smtpClose();
|
|
|
|
Log::info('SMTP connection successful with fallback (no encryption)');
|
|
return true;
|
|
|
|
} catch (Exception $fallbackError) {
|
|
Log::error('SMTP connection test failed completely', [
|
|
'original_error' => $e->getMessage(),
|
|
'fallback_error' => $fallbackError->getMessage()
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dapatkan instance PHPMailer
|
|
*
|
|
* @return PHPMailer
|
|
*/
|
|
public function getMailer(): PHPMailer
|
|
{
|
|
return $this->mailer;
|
|
}
|
|
}
|