update coba resend
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
16ca1eead7
commit
ca8a8c6c15
19
.env.example
19
.env.example
|
|
@ -47,15 +47,18 @@ REDIS_HOST=127.0.0.1
|
||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
# MAIL_MAILER=smtp
|
||||||
MAIL_HOST=smtp.gmail.com
|
# MAIL_HOST=smtp.gmail.com
|
||||||
MAIL_PORT=587
|
# MAIL_PORT=587
|
||||||
MAIL_ENCRYPTION=tls
|
# MAIL_ENCRYPTION=tls
|
||||||
MAIL_USERNAME=rimasazkya@gmail.com
|
# MAIL_USERNAME=rimasazkya@gmail.com
|
||||||
MAIL_PASSWORD="uamw iegn gjtg dkuw"
|
# MAIL_PASSWORD="uamw iegn gjtg dkuw"
|
||||||
MAIL_FROM_ADDRESS=SiJentik@noreply.com
|
# MAIL_FROM_ADDRESS=SiJentik@noreply.com
|
||||||
# MAIL_FROM_NAME="${APP_NAME}"
|
# MAIL_FROM_NAME="${APP_NAME}"
|
||||||
MAIL_FROM_NAME="SiJentik"
|
# MAIL_FROM_NAME="SiJentik"
|
||||||
|
RESEND_API_KEY=re_TSzu3Bt8_F8akQaw1DeNWvnbvUpJs2XLk
|
||||||
|
MAIL_MAILER=resend_curl
|
||||||
|
|
||||||
|
|
||||||
AWS_ACCESS_KEY_ID=
|
AWS_ACCESS_KEY_ID=
|
||||||
AWS_SECRET_ACCESS_KEY=
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Mail\OtpMail;
|
use App\Mail\OtpMail;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class OtpController extends Controller
|
class OtpController extends Controller
|
||||||
|
|
@ -33,7 +32,6 @@ public function sendOtp(Request $request)
|
||||||
Log::info("OTP DB: $otp");
|
Log::info("OTP DB: $otp");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
set_time_limit(120);
|
|
||||||
Mail::to($user->email)->send(new OtpMail($otp));
|
Mail::to($user->email)->send(new OtpMail($otp));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::error($e->getMessage());
|
Log::error($e->getMessage());
|
||||||
|
|
@ -79,4 +77,4 @@ public function verifyOtp(Request $request)
|
||||||
|
|
||||||
return response()->json(['message' => 'OTP valid'], 200);
|
return response()->json(['message' => 'OTP valid'], 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,6 @@ public function __construct($otp)
|
||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
->from(env('MAIL_FROM_ADDRESS', 'rifaulardiyanto@gmail.com'))
|
|
||||||
->subject('Kode OTP Anda')
|
->subject('Kode OTP Anda')
|
||||||
->view('emails.otp')
|
->view('emails.otp')
|
||||||
->with(['otp' => $this->otp]);
|
->with(['otp' => $this->otp]);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail\Transport;
|
||||||
|
|
||||||
|
use App\Services\ResendEmailService;
|
||||||
|
use Symfony\Component\Mailer\Exception\TransportException;
|
||||||
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransport;
|
||||||
|
use Symfony\Component\Mime\Email;
|
||||||
|
|
||||||
|
class ResendCurlTransport extends AbstractTransport
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly ResendEmailService $service,
|
||||||
|
private readonly string $defaultFromAddress,
|
||||||
|
private readonly ?string $defaultFromName = null,
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return 'resend_curl';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doSend(SentMessage $message): void
|
||||||
|
{
|
||||||
|
$originalMessage = $message->getOriginalMessage();
|
||||||
|
|
||||||
|
if (! $originalMessage instanceof Email) {
|
||||||
|
throw new TransportException('Resend transport hanya mendukung Symfony Email.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$fromAddresses = $originalMessage->getFrom();
|
||||||
|
$from = $fromAddresses !== []
|
||||||
|
? $this->stringifyAddresses([$fromAddresses[0]])[0]
|
||||||
|
: $this->formatFrom($this->defaultFromAddress, $this->defaultFromName);
|
||||||
|
|
||||||
|
$to = $this->stringifyAddresses($originalMessage->getTo());
|
||||||
|
|
||||||
|
if ($to === []) {
|
||||||
|
throw new TransportException('Penerima email kosong.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'from' => $from,
|
||||||
|
'to' => count($to) === 1 ? $to[0] : $to,
|
||||||
|
'subject' => $originalMessage->getSubject() ?? '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$htmlBody = $this->normalizeBody($originalMessage->getHtmlBody());
|
||||||
|
$textBody = $this->normalizeBody($originalMessage->getTextBody());
|
||||||
|
|
||||||
|
if ($htmlBody !== null) {
|
||||||
|
$payload['html'] = $htmlBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($textBody !== null) {
|
||||||
|
$payload['text'] = $textBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->service->send($payload);
|
||||||
|
|
||||||
|
if (isset($response['id']) && is_string($response['id'])) {
|
||||||
|
$message->setMessageId($response['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message->appendDebug(json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formatFrom(string $address, ?string $name): string
|
||||||
|
{
|
||||||
|
return $name ? sprintf('%s <%s>', $name, $address) : $address;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeBody(mixed $body): ?string
|
||||||
|
{
|
||||||
|
if ($body === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_resource($body)) {
|
||||||
|
$body = stream_get_contents($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_string($body)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = trim($body);
|
||||||
|
|
||||||
|
return $body === '' ? null : $body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Mail\Transport\ResendCurlTransport;
|
||||||
|
use App\Services\ResendEmailService;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
|
|
@ -19,6 +22,12 @@ public function register(): void
|
||||||
*/
|
*/
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
//
|
Mail::extend('resend_curl', function (array $config = []) {
|
||||||
|
return new ResendCurlTransport(
|
||||||
|
app(ResendEmailService::class),
|
||||||
|
$config['from']['address'] ?? config('mail.from.address'),
|
||||||
|
$config['from']['name'] ?? config('mail.from.name')
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
class ResendEmailService
|
||||||
|
{
|
||||||
|
private string $endpoint = 'https://api.resend.com/emails';
|
||||||
|
|
||||||
|
public function send(array $payload): array
|
||||||
|
{
|
||||||
|
$apiKey = config('services.resend.key');
|
||||||
|
|
||||||
|
if (! $apiKey) {
|
||||||
|
throw new RuntimeException('RESEND_API_KEY belum diatur.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
if ($body === false) {
|
||||||
|
throw new RuntimeException('Gagal menyiapkan payload email untuk Resend.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$ch = curl_init($this->endpoint);
|
||||||
|
|
||||||
|
if ($ch === false) {
|
||||||
|
throw new RuntimeException('Gagal inisialisasi cURL.');
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_HTTPHEADER => [
|
||||||
|
'Authorization: Bearer '.$apiKey,
|
||||||
|
'Content-Type: application/json',
|
||||||
|
],
|
||||||
|
CURLOPT_POSTFIELDS => $body,
|
||||||
|
CURLOPT_CONNECTTIMEOUT => 10,
|
||||||
|
CURLOPT_TIMEOUT => 30,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$statusCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if ($response === false) {
|
||||||
|
$error = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
throw new RuntimeException('Resend request gagal: '.$error);
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
$decoded = json_decode($response, true);
|
||||||
|
|
||||||
|
if ($statusCode < 200 || $statusCode >= 300) {
|
||||||
|
$message = is_array($decoded) && isset($decoded['message'])
|
||||||
|
? $decoded['message']
|
||||||
|
: $response;
|
||||||
|
|
||||||
|
throw new RuntimeException('Resend API error: '.$message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_array($decoded) ? $decoded : ['raw' => $response];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/sanctum": "^4.3",
|
"laravel/sanctum": "^4.3",
|
||||||
"laravel/tinker": "^2.10.1"
|
"laravel/tinker": "^2.10.1",
|
||||||
|
"resend/resend-php": "^1.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.23",
|
"fakerphp/faker": "^1.23",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "ad91ab9bde70e3576f2b64dd11542bc4",
|
"content-hash": "94cb2ce06c9e2860c6251ecd8f0072c3",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
|
|
@ -3357,6 +3357,63 @@
|
||||||
},
|
},
|
||||||
"time": "2025-12-14T04:43:48+00:00"
|
"time": "2025-12-14T04:43:48+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "resend/resend-php",
|
||||||
|
"version": "v1.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/resend/resend-php.git",
|
||||||
|
"reference": "87d29d98271a0ab1c09cdbee102daa2f9b3419db"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/resend/resend-php/zipball/87d29d98271a0ab1c09cdbee102daa2f9b3419db",
|
||||||
|
"reference": "87d29d98271a0ab1c09cdbee102daa2f9b3419db",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"guzzlehttp/guzzle": "^7.5",
|
||||||
|
"php": "^8.1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.13",
|
||||||
|
"mockery/mockery": "^1.6",
|
||||||
|
"pestphp/pest": "^1.0|^2.0|^3.0|^4.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/Resend.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Resend\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Resend and contributors",
|
||||||
|
"homepage": "https://github.com/resend/resend-php/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Resend PHP library.",
|
||||||
|
"homepage": "https://resend.com/",
|
||||||
|
"keywords": [
|
||||||
|
"api",
|
||||||
|
"client",
|
||||||
|
"php",
|
||||||
|
"resend",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/resend/resend-php/issues",
|
||||||
|
"source": "https://github.com/resend/resend-php/tree/v1.3.0"
|
||||||
|
},
|
||||||
|
"time": "2026-04-11T10:48:32+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/clock",
|
"name": "symfony/clock",
|
||||||
"version": "v7.4.0",
|
"version": "v7.4.0",
|
||||||
|
|
@ -8456,5 +8513,5 @@
|
||||||
"php": "^8.2"
|
"php": "^8.2"
|
||||||
},
|
},
|
||||||
"platform-dev": {},
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.6.0"
|
"plugin-api-version": "2.9.0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'default' => env('MAIL_MAILER', 'log'),
|
'default' => env('MAIL_MAILER', 'resend_curl'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
@ -65,6 +65,10 @@
|
||||||
'transport' => 'resend',
|
'transport' => 'resend',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'resend_curl' => [
|
||||||
|
'transport' => 'resend_curl',
|
||||||
|
],
|
||||||
|
|
||||||
'sendmail' => [
|
'sendmail' => [
|
||||||
'transport' => 'sendmail',
|
'transport' => 'sendmail',
|
||||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue