1

Please explain conception how to sign outgoing emails in Laravel 9 with a DKIM signature. Laravel 9 uses Symfony mailer. I'm trying to proceed by this way:

class ContactForm extends Mailable
{
    use Queueable, SerializesModels;

    public $mailData;

    public function __construct($mailData)
    {
        $this->mailData = $mailData;
    }

    public function build()
    {
        $this->subject($this->mailData['subject'])
            ->view('mail.contact-form')
            ->text('mail.contact-form_plain');

        $this->withSymfonyMessage(function (Email $message) {
            $signer = new DkimSigner(config('mail.dkim_private_key'), config('mail.dkim_domain'),
            config('mail.dkim_selector'));
            $signer->sign($message);
        });

        return $this;
    }
}

Error

local.ERROR: A message must have a text or an HTML part or attachments. {"exception":"[object] (Symfony\Component\Mime\Exception\LogicException(code: 0): A message must have a text or an HTML part or attachments. at E:\WebProjects\domains\hostbrook\vendor\symfony\mime\Email.php:390)

Karl Hill
  • 12,937
  • 5
  • 58
  • 95
HostBrook
  • 13
  • 3
  • I have the same problem, can I know where did you use the build function? I'm using Mail::send() in another php code – John Sall Nov 02 '22 at 07:31

2 Answers2

1

There is other way to sign outgoing emails in Laravel 9 with a DKIM signature (without any tool):

class ContactForm extends Mailable
{
    use Queueable, SerializesModels;

    public $mailData;

    public function __construct($mailData)
    {
        $this->mailData = $mailData;
    }

    public function build()
    {
        $mailData = $this->mailData;

        $htmlView = 'mail.contact-form';
        $plainView = 'mail.contact-form_plain';

        $htmlEmail = view($htmlView, compact('mailData'))->render();
        $plainEmail = view($plainView, compact('mailData'))->render();

        return $this->subject($this->mailData['subject'])
            ->view($htmlView)
            ->text($plainView)
            ->withSymfonyMessage(function (Email $message) use ($htmlEmail, $plainEmail) {
                $message
                    ->html($htmlEmail)
                    ->text($plainEmail);

                $signer = new DkimSigner(
                    config('mail.dkim_private_key'),
                    config('mail.dkim_domain'),
                    config('mail.dkim_selector')
                );

                $signedEmail = $signer->sign($message);

                $message->setHeaders($signedEmail->getHeaders());
            });
    }
}
  • 1
    Well, I have marked your answer as a solution because this is exactly how needs to be signed. Thanks for that. But the problem is, it doesn't work if both HTML and plain View are used to build email. In this case DKIM is signed but not valid. This is a known error Simfony mailer and looks like we can not do anything with it until Laravel Team fix it. But if email build either with HTML or Plain text only - this solution works. – HostBrook May 01 '22 at 18:19
-2

There is a tool that will solve your problem. You can get it here and this is how you use it:

Install package with composer using: composer require simonschaufi/laravel-dkim

In the config/app.php file, comment Illuminate\Mail\MailServiceProvider::class line and add the following line with dkim package service provider: SimonSchaufi\LaravelDKIM\DKIMMailServiceProvider::class

Publish the config file using the artisan command: php artisan vendor:publish --provider="SimonSchaufi\LaravelDKIM\DKIMMailServiceProvider"

Configure your dkim settings in your .env file:

DKIM_PRIVATE_KEY=your_txt_private_key_path // Required. Indicates your private key txt file configured previously. By default, the storage path app/dkim/private_key.txt is used
DKIM_SELECTOR=your_dkim_record_selector // Required. If this value is empty, <code>default</code> is used
DKIM_DOMAIN=your_dkim_domain // Required. Indicates the domain of your dkim record configured previously
DKIM_PASSPHRASE=your_dkim_passphrase // Optional
DKIM_ALGORITHM=your_dkim_algorithm // Required. By default, rsa-sha256 is used
DKIM_IDENTITY=your_dkim_identity // Optional

This tool solves the problem using a custom Mailer with dkim signature:

$signer = new DkimSigner(file_get_contents($privateKey), $domain, $selector, [], config('dkim.passphrase'));
$signedEmail = $signer->sign($message->getSymfonyMessage());
$symfonyMessage->setHeaders($signedEmail->getHeaders());
  • Please don't just post some tool or library as an answer. At least demonstrate [how it solves the problem](//meta.stackoverflow.com/a/251605) in the answer itself. – cigien Apr 09 '22 at 14:28