我正在为 Laravel 集成 Azure 通信服务电子邮件,当然,我已经创建了帐户、添加了域、验证了 SPF 和 DKIM,之后添加到我的 config/services.php 中
'azure' => [
'endpoint' => env('AZURE_ENDPOINT'),
'accessKey' => env('AZURE_ACCESS_KEY'),
]
能够使用我添加到 .env 中的凭据,在本例中是这样的示例:
#Configuration using Azure Communications Services for Email
AZURE_ENDPOINT=https://laravel.unitedstates.communication.azure.com
AZURE_ACCESS_KEY=Ie2zAasb56t4ht86u7axRLh
在此之后,我为连接创建了一个服务
<?php
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class AzureEmailService
{
protected $client;
protected $endpoint;
protected $accessKey;
public function __construct()
{
$this->client = new Client();
$this->endpoint = config('services.azure.endpoint');
$this->accessKey = config('services.azure.accessKey');
}
public function sendEmail($to, $subject, $body)
{
$url = "{$this->endpoint}/emails:send?api-version=2021-10-01-preview";
//dd($url);
$headers = [
'Authorization' => 'Bearer ' . $this->accessKey,
'Content-Type' => 'application/json',
];
$payload = [
'senderAddress' => '[email protected]', //dirección de envío
'recipients' => [
'to' => [
['address' => $to], // la API
],
],
'content' => [
'subject' => $subject,
'plainText' => $body, // Cambia aquí si quiero usar HTML
],
];
try {
$response = $this->client->post($url, [
'headers' => $headers,
'json' => $payload,
]);
return json_decode($response->getBody()->getContents());
} catch (RequestException $e) {
\Log::error('Error al enviar el email: ', ['error' => $e->getMessage()]);
throw new \Exception("Error al enviar el email", 500);
}
}
}
此后我创建了一个 Livewire 组件:
class SendEmailForm extends Component
{
public $email;
public $subject;
public $body;
//validaciones basicas
protected $rules = [
'email' => 'required|email',
'subject' => 'required|string|max:255',
'body' => 'required|string',
];
// Método para enviar el email
public function sendEmail(AzureEmailService $azureEmailService)
{
// Validamos el formulario antes de enviar
$this->validate();
try {
// Llamamos al servicio Azure para enviar el email
$azureEmailService->sendEmail($this->email, $this->subject, $this->body);
// Si el email se envía correctamente, mostramos un mensaje de éxito
session()->flash('success', 'Email enviado correctamente.');
} catch (\Exception $e) {
// Si hay un error, lo mostramos
session()->flash('error', 'Error al enviar el email: ' . $e->getMessage());
}
}
public function render()
{
return view('livewire.send-email-form');
}
}
将其连接到包含用于发送电子邮件的表单的视图
<div class="max-w-xl mx-auto p-6 bg-white shadow-md rounded-md">
@if (session()->has('success'))
<div class="text-green-500 mb-4">
{{ session('success') }}
</div>
@endif
@if (session()->has('error'))
<div class="text-red-500 mb-4">
{{ session('error') }}
</div>
@endif
<form wire:submit.prevent="sendEmail">
<div class="mb-4">
<label for="email" class="block text-gray-700">Email:</label>
<input type="email" id="email" wire:model="email" class="w-full border-gray-300 rounded-md shadow-sm" required>
@error('email') <span class="text-red-500">{{ $message }}</span> @enderror
</div>
<div class="mb-4">
<label for="subject" class="block text-gray-700">Asunto:</label>
<input type="text" id="subject" wire:model="subject" class="w-full border-gray-300 rounded-md shadow-sm" required>
@error('subject') <span class="text-red-500">{{ $message }}</span> @enderror
</div>
<div class="mb-4">
<label for="body" class="block text-gray-700">Mensaje:</label>
<textarea id="body" wire:model="body" class="w-full border-gray-300 rounded-md shadow-sm" rows="4" required></textarea>
@error('body') <span class="text-red-500">{{ $message }}</span> @enderror
</div>
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Enviar Email
</button>
</form>
</div>
但是发送时,我收到此错误:
[2024-10-18 06:22:19] local.ERROR: Error al enviar el email: {"error":"Client error: `POST https://laravel.unitedstates.communication.azure.com/emails:send?api-version=2021-10-01-preview` resulted in a `401 Unauthorized` response:
{\"error\":{\"code\":\"Denied\",\"message\":\"Denied by the resource provider.\"}}
"}
显然该错误表明我没有授权,但我不明白我是否应该在此过程中配置其他内容,是否在访问之前创建令牌或类似的东西......这些情况的文档不是很清楚,在这种情况下,我的连接是通过 cURL 但其他方式是使用包或 SDK,因此由于这个原因,信息对我来说不是很清楚......
如何正确连接?或者我跳过了某些步骤?
我希望我可以解决问题,以纠正使用Azure API发送电子邮件的正确配置
您应该从 Azure Active Directory 获取 OAuth 2.0 令牌并将其用作不记名令牌,而不是使用
Authorization
标头中的访问密钥。
Client ID
、Tenant ID
和 Client Secret
。Guzzle
等库或 Laravel 的 league/oauth2-client
包来获取令牌。Guzzle 请求获取令牌:
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class AzureEmailService
{
protected $client;
protected $endpoint;
protected $clientId;
protected $clientSecret;
protected $tenantId;
public function __construct()
{
$this->client = new Client();
$this->endpoint = config('services.azure.endpoint');
$this->clientId = env('AZURE_CLIENT_ID');
$this->clientSecret = env('AZURE_CLIENT_SECRET');
$this->tenantId = env('AZURE_TENANT_ID');
}
// Function to get the OAuth 2.0 token from Azure AD
protected function getAccessToken()
{
$url = 'https://login.microsoftonline.com/' . $this->tenantId . '/oauth2/v2.0/token';
try {
$response = $this->client->post($url, [
'form_params' => [
'grant_type' => 'client_credentials',
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'scope' => 'https://communication.azure.com/.default',
],
]);
$data = json_decode($response->getBody(), true);
return $data['access_token'];
} catch (RequestException $e) {
\Log::error('Failed to get Azure OAuth Token: ', ['error' => $e->getMessage()]);
throw new \Exception("Failed to get access token from Azure", 500);
}
}
// Function to send the email
public function sendEmail($to, $subject, $body)
{
$accessToken = $this->getAccessToken(); // Obtain access token
$url = "{$this->endpoint}/emails:send?api-version=2021-10-01-preview";
$headers = [
'Authorization' => 'Bearer ' . $accessToken,
'Content-Type' => 'application/json',
];
$payload = [
'senderAddress' => '[email protected]',
'recipients' => [
'to' => [
['address' => $to],
],
],
'content' => [
'subject' => $subject,
'plainText' => $body,
],
];
try {
$response = $this->client->post($url, [
'headers' => $headers,
'json' => $payload,
]);
return json_decode($response->getBody()->getContents());
} catch (RequestException $e) {
\Log::error('Error sending email: ', ['error' => $e->getMessage()]);
throw new \Exception("Error sending email", 500);
}
}
}
认证成功。
结果: