mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-06 21:21:23 +00:00
Upgrade mail configuration (#455)
* Upgrade the mail configuration * Update mail configuration to match Laravel 12 * Update mail configuration to properly set none or null * Pint code * Upgrade Symfony Mailers
This commit is contained in:
committed by
GitHub
parent
d1bca362de
commit
bae8dbe083
@@ -35,7 +35,7 @@ REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=
|
||||
MAIL_PORT=
|
||||
MAIL_USERNAME=
|
||||
|
||||
@@ -3,7 +3,7 @@ APP_DEBUG=true
|
||||
APP_KEY=base64:IdDlpLmYyWA9z4Ruj5st1FSYrhCR7lPOscLGCz2Jf4I=
|
||||
DB_CONNECTION=sqlite
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=ff538f0e1037f4
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Http\Requests\MailEnvironmentRequest;
|
||||
use App\Mail\TestMail;
|
||||
use App\Models\Setting;
|
||||
use App\Space\EnvironmentManager;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Mail;
|
||||
@@ -14,17 +15,26 @@ use Mail;
|
||||
class MailConfigurationController extends Controller
|
||||
{
|
||||
/**
|
||||
* The environment manager
|
||||
*
|
||||
* @var EnvironmentManager
|
||||
*/
|
||||
protected $environmentManager;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*/
|
||||
public function __construct(EnvironmentManager $environmentManager)
|
||||
{
|
||||
$this->environmentManager = $environmentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the mail environment variables
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
public function saveMailEnvironment(MailEnvironmentRequest $request)
|
||||
{
|
||||
@@ -40,32 +50,79 @@ class MailConfigurationController extends Controller
|
||||
return response()->json($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mail environment variables
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
public function getMailEnvironment()
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$driver = config('mail.default');
|
||||
|
||||
// Base data that's always available
|
||||
$MailData = [
|
||||
'mail_driver' => config('mail.driver'),
|
||||
'mail_host' => config('mail.host'),
|
||||
'mail_port' => config('mail.port'),
|
||||
'mail_username' => config('mail.username'),
|
||||
'mail_password' => config('mail.password'),
|
||||
'mail_encryption' => is_null(config('mail.encryption')) ? 'none' : config('mail.encryption'),
|
||||
'mail_driver' => $driver,
|
||||
'from_name' => config('mail.from.name'),
|
||||
'from_mail' => config('mail.from.address'),
|
||||
'mail_mailgun_endpoint' => config('services.mailgun.endpoint'),
|
||||
'mail_mailgun_domain' => config('services.mailgun.domain'),
|
||||
'mail_mailgun_secret' => config('services.mailgun.secret'),
|
||||
'mail_ses_key' => config('services.ses.key'),
|
||||
'mail_ses_secret' => config('services.ses.secret'),
|
||||
'mail_ses_region' => config('services.ses.region'),
|
||||
];
|
||||
|
||||
// Driver-specific configuration
|
||||
switch ($driver) {
|
||||
case 'smtp':
|
||||
$MailData = array_merge($MailData, [
|
||||
'mail_host' => config('mail.mailers.smtp.host'),
|
||||
'mail_port' => config('mail.mailers.smtp.port'),
|
||||
'mail_username' => config('mail.mailers.smtp.username'),
|
||||
'mail_password' => config('mail.mailers.smtp.password'),
|
||||
'mail_encryption' => config('mail.mailers.smtp.scheme') ?? 'none',
|
||||
'mail_scheme' => config('mail.mailers.smtp.scheme'),
|
||||
'mail_url' => config('mail.mailers.smtp.url'),
|
||||
'mail_timeout' => config('mail.mailers.smtp.timeout'),
|
||||
'mail_local_domain' => config('mail.mailers.smtp.local_domain'),
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'mailgun':
|
||||
$MailData = array_merge($MailData, [
|
||||
'mail_mailgun_domain' => config('mail.mailers.mailgun.domain'),
|
||||
'mail_mailgun_secret' => config('mail.mailers.mailgun.secret'),
|
||||
'mail_mailgun_endpoint' => config('mail.mailers.mailgun.endpoint'),
|
||||
'mail_mailgun_scheme' => config('mail.mailers.mailgun.scheme'),
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'ses':
|
||||
$MailData = array_merge($MailData, [
|
||||
'mail_ses_key' => config('services.ses.key'),
|
||||
'mail_ses_secret' => config('services.ses.secret'),
|
||||
'mail_ses_region' => config('services.ses.region'),
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'sendmail':
|
||||
$MailData = array_merge($MailData, [
|
||||
'mail_sendmail_path' => config('mail.mailers.sendmail.path'),
|
||||
]);
|
||||
break;
|
||||
|
||||
default:
|
||||
// For unknown drivers, return minimal configuration
|
||||
break;
|
||||
}
|
||||
|
||||
return response()->json($MailData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the available mail drivers
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
public function getMailDrivers()
|
||||
{
|
||||
@@ -82,6 +139,14 @@ class MailConfigurationController extends Controller
|
||||
return response()->json($drivers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the email configuration
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function testEmailConfig(Request $request)
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
@@ -34,7 +34,7 @@ class MailEnvironmentRequest extends FormRequest
|
||||
'required',
|
||||
],
|
||||
'mail_encryption' => [
|
||||
'required',
|
||||
'nullable',
|
||||
'string',
|
||||
],
|
||||
'from_name' => [
|
||||
|
||||
@@ -26,7 +26,7 @@ class EnvironmentManager
|
||||
/**
|
||||
* Set the .env and .env.example paths.
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct($path = null)
|
||||
{
|
||||
$this->envPath = base_path('.env');
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class EnvironmentManager
|
||||
|
||||
// Check if new or old key
|
||||
if ($entry[0] == $data_key) {
|
||||
$env[$env_key] = $data_key.'='.$this->encode($data_value);
|
||||
$env[$env_key] = sprintf('%s=%s', $data_key, $this->encode($data_value));
|
||||
$updated = true;
|
||||
}
|
||||
}
|
||||
@@ -89,8 +89,25 @@ class EnvironmentManager
|
||||
*/
|
||||
private function encode($str)
|
||||
{
|
||||
// Convert to string if not already
|
||||
$str = (string) $str;
|
||||
|
||||
if ((strpos($str, ' ') !== false || preg_match('/'.preg_quote('^\'£$%^&*()}{@#~?><,@|-=-_+-¬', '/').'/', $str)) && ($str[0] != '"' || $str[strlen($str) - 1] != '"')) {
|
||||
// If the value is already properly quoted, return as is
|
||||
if (strlen($str) >= 2 && $str[0] === '"' && $str[strlen($str) - 1] === '"') {
|
||||
return $str;
|
||||
}
|
||||
|
||||
// Check if the value contains characters that need quoting
|
||||
// Using a character class regex to properly match special characters
|
||||
$specialChars = '\^\'£$%&*()}{@#~?><,|=\-_+¬!';
|
||||
$needsQuoting = (
|
||||
strpos($str, ' ') !== false ||
|
||||
preg_match('/['.preg_quote($specialChars, '/').']/', $str)
|
||||
);
|
||||
|
||||
if ($needsQuoting) {
|
||||
// Escape any existing double quotes in the string
|
||||
$str = str_replace('"', '\\"', $str);
|
||||
$str = '"'.$str.'"';
|
||||
}
|
||||
|
||||
@@ -314,12 +331,12 @@ class EnvironmentManager
|
||||
case 'smtp':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_DRIVER' => $request->get('mail_driver'),
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'MAIL_HOST' => $request->get('mail_host'),
|
||||
'MAIL_PORT' => $request->get('mail_port'),
|
||||
'MAIL_USERNAME' => $request->get('mail_username'),
|
||||
'MAIL_PASSWORD' => $request->get('mail_password'),
|
||||
'MAIL_ENCRYPTION' => $request->get('mail_encryption') !== 'none' ? $request->get('mail_encryption') : 'null',
|
||||
'MAIL_SCHEME' => $request->get('mail_encryption') !== 'none' ? $request->get('mail_encryption') : 'null',
|
||||
'MAIL_FROM_ADDRESS' => $request->get('from_mail'),
|
||||
'MAIL_FROM_NAME' => $request->get('from_name'),
|
||||
];
|
||||
@@ -329,12 +346,11 @@ class EnvironmentManager
|
||||
case 'mailgun':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_DRIVER' => $request->get('mail_driver'),
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'MAIL_HOST' => $request->get('mail_host'),
|
||||
'MAIL_PORT' => $request->get('mail_port'),
|
||||
'MAIL_USERNAME' => config('mail.username'),
|
||||
'MAIL_PASSWORD' => config('mail.password'),
|
||||
'MAIL_ENCRYPTION' => $request->get('mail_encryption'),
|
||||
'MAIL_FROM_ADDRESS' => $request->get('from_mail'),
|
||||
'MAIL_FROM_NAME' => $request->get('from_name'),
|
||||
'MAILGUN_DOMAIN' => $request->get('mail_mailgun_domain'),
|
||||
@@ -347,7 +363,7 @@ class EnvironmentManager
|
||||
case 'ses':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_DRIVER' => $request->get('mail_driver'),
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'MAIL_HOST' => $request->get('mail_host'),
|
||||
'MAIL_PORT' => $request->get('mail_port'),
|
||||
'MAIL_USERNAME' => config('mail.username'),
|
||||
@@ -366,7 +382,7 @@ class EnvironmentManager
|
||||
case 'mail':
|
||||
|
||||
$mailEnv = [
|
||||
'MAIL_DRIVER' => $request->get('mail_driver'),
|
||||
'MAIL_MAILER' => $request->get('mail_driver'),
|
||||
'MAIL_HOST' => config('mail.host'),
|
||||
'MAIL_PORT' => config('mail.port'),
|
||||
'MAIL_USERNAME' => config('mail.username'),
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"spatie/flysystem-dropbox": "^3.0",
|
||||
"spatie/laravel-backup": "^9.2.9",
|
||||
"spatie/laravel-medialibrary": "^11.11",
|
||||
"symfony/mailer": "^7.3",
|
||||
"symfony/mailgun-mailer": "^7.3",
|
||||
"vinkla/hashids": "^13.0.0"
|
||||
},
|
||||
|
||||
18
composer.lock
generated
18
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "55a74107ca176346bd153f73881910bb",
|
||||
"content-hash": "a4ddf34cf22d150b595d8259e4152dd2",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-crt-php",
|
||||
@@ -8383,16 +8383,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailer",
|
||||
"version": "v7.2.6",
|
||||
"version": "v7.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mailer.git",
|
||||
"reference": "998692469d6e698c6eadc7ef37a6530a9eabb356"
|
||||
"reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mailer/zipball/998692469d6e698c6eadc7ef37a6530a9eabb356",
|
||||
"reference": "998692469d6e698c6eadc7ef37a6530a9eabb356",
|
||||
"url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575",
|
||||
"reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8443,7 +8443,7 @@
|
||||
"description": "Helps sending emails",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mailer/tree/v7.2.6"
|
||||
"source": "https://github.com/symfony/mailer/tree/v7.3.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8454,12 +8454,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-04T09:50:51+00:00"
|
||||
"time": "2025-08-13T11:49:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailgun-mailer",
|
||||
|
||||
121
config/mail.php
121
config/mail.php
@@ -2,20 +2,125 @@
|
||||
|
||||
return [
|
||||
|
||||
'driver' => env('MAIL_DRIVER', 'smtp'),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mailer
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default mailer that is used to send all email
|
||||
| messages unless another mailer is explicitly specified when sending
|
||||
| the message. All additional mailers can be configured within the
|
||||
| "mailers" array. Examples of each type of mailer are provided.
|
||||
|
|
||||
*/
|
||||
|
||||
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
|
||||
'default' => env('MAIL_MAILER', 'log'),
|
||||
|
||||
'port' => env('MAIL_PORT', 587),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mailer Configurations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure all of the mailers used by your application plus
|
||||
| their respective settings. Several examples have been configured for
|
||||
| you and you are free to add your own as your application requires.
|
||||
|
|
||||
| Laravel supports a variety of mail "transport" drivers that can be used
|
||||
| when delivering an email. You may specify which one you're using for
|
||||
| your mailers below. You may also add additional mailers if needed.
|
||||
|
|
||||
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
|
||||
| "postmark", "resend", "log", "array",
|
||||
| "failover", "roundrobin"
|
||||
|
|
||||
*/
|
||||
|
||||
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
|
||||
'mailers' => [
|
||||
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'smtp' => [
|
||||
'transport' => 'smtp',
|
||||
'encryption' => env('MAIL_ENCRYPTION', 'none'),
|
||||
'scheme' => env('MAIL_SCHEME'),
|
||||
'url' => env('MAIL_URL'),
|
||||
'host' => env('MAIL_HOST', '127.0.0.1'),
|
||||
'port' => env('MAIL_PORT', 2525),
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'timeout' => null,
|
||||
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url((string) env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
|
||||
],
|
||||
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'mailgun' => [
|
||||
'domain' => env('MAILGUN_DOMAIN'),
|
||||
'secret' => env('MAILGUN_SECRET'),
|
||||
'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
|
||||
'scheme' => 'https',
|
||||
],
|
||||
|
||||
'sendmail' => '/usr/sbin/sendmail -bs',
|
||||
'ses' => [
|
||||
'transport' => 'ses',
|
||||
],
|
||||
|
||||
'log_channel' => env('MAIL_LOG_CHANNEL'),
|
||||
'postmark' => [
|
||||
'transport' => 'postmark',
|
||||
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
|
||||
// 'client' => [
|
||||
// 'timeout' => 5,
|
||||
// ],
|
||||
],
|
||||
|
||||
'resend' => [
|
||||
'transport' => 'resend',
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
'transport' => 'sendmail',
|
||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'transport' => 'log',
|
||||
'channel' => env('MAIL_LOG_CHANNEL'),
|
||||
],
|
||||
|
||||
'array' => [
|
||||
'transport' => 'array',
|
||||
],
|
||||
|
||||
'failover' => [
|
||||
'transport' => 'failover',
|
||||
'mailers' => [
|
||||
'smtp',
|
||||
'log',
|
||||
],
|
||||
'retry_after' => 60,
|
||||
],
|
||||
|
||||
'roundrobin' => [
|
||||
'transport' => 'roundrobin',
|
||||
'mailers' => [
|
||||
'ses',
|
||||
'postmark',
|
||||
],
|
||||
'retry_after' => 60,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global "From" Address
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You may wish for all emails sent by your application to be sent from
|
||||
| the same address. Here you may specify a name and address that is
|
||||
| used globally for all emails that are sent by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'from' => [
|
||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@invoiceshelf.com'),
|
||||
'name' => env('MAIL_FROM_NAME', 'InvoiceShelf'),
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -38,7 +38,6 @@ export const useMailDriverStore = (useWindow = false) => {
|
||||
mail_ses_key: '',
|
||||
mail_ses_secret: '',
|
||||
mail_ses_region: '',
|
||||
mail_encryption: 'tls',
|
||||
from_mail: '',
|
||||
from_name: '',
|
||||
},
|
||||
@@ -49,7 +48,7 @@ export const useMailDriverStore = (useWindow = false) => {
|
||||
mail_port: null,
|
||||
mail_username: '',
|
||||
mail_password: '',
|
||||
mail_encryption: 'tls',
|
||||
mail_encryption: '',
|
||||
from_mail: '',
|
||||
from_name: '',
|
||||
},
|
||||
|
||||
@@ -93,21 +93,14 @@
|
||||
<BaseInputGroup
|
||||
:label="$t('settings.mail.encryption')"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:error="
|
||||
v$.smtpConfig.mail_encryption.$error &&
|
||||
v$.smtpConfig.mail_encryption.$errors[0].$message
|
||||
"
|
||||
required
|
||||
>
|
||||
<BaseMultiselect
|
||||
v-model.trim="mailDriverStore.smtpConfig.mail_encryption"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:options="encryptions"
|
||||
:options="schemes"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
placeholder="Select option"
|
||||
:invalid="v$.smtpConfig.mail_encryption.$error"
|
||||
@input="v$.smtpConfig.mail_encryption.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
@@ -204,7 +197,7 @@ const mailDriverStore = useMailDriverStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
let isShowPassword = ref(false)
|
||||
const encryptions = reactive(['none','tls', 'ssl', 'starttls'])
|
||||
const schemes = reactive(['smtp', 'smtps', 'none'])
|
||||
|
||||
const getInputType = computed(() => {
|
||||
if (isShowPassword.value) {
|
||||
@@ -226,9 +219,6 @@ const rules = computed(() => {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
numeric: helpers.withMessage(t('validation.numbers_only'), numeric),
|
||||
},
|
||||
mail_encryption: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
from_mail: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
email: helpers.withMessage(t('validation.email_incorrect'), email),
|
||||
|
||||
Reference in New Issue
Block a user