encrypt emails with s/mime on PHP and send with PHPMailer over smtp

2024-01-25 PHP

php mail can sign messages but not encrypt them.
For a project, I have to encrypt the mail Body with php.

First, I have to receive the public key from the recipient.
In my case, I test it with the s/mime certificate of my post box.

Here are the message body and the header parameters:

$headers = array(
    "To" => "mail@falk-m.de",
    "From" => "testsender@falk-m.de",
    "Subject" => "a encrypted message.",
);

$message = "this is a secred text";

For the encryption method, we need the message text in a file and we need a file for the encryption output.

$tempBodyFile = @tempnam("temp", "email");
file_put_contents($tempBodyFile, $message);

$tempEncfFile = @tempnam("temp", "emailenc");

Read the certificate from the recipient to a string variable.

$pubkey = file_get_contents(__DIR__ . "/certificate.crt");

If you want to signate the message, then use first the openssl_pkcs7_sign function to signate the content, before you encrypt the content with the openssl_pkcs7_encrypt function.
You find some examples on the internet. In my case, this is not necessary, because I only want to encrypt the content.
I want a secure transport of sensitive data, not the verification from the sender of the mail.

Now, we use an openssl function for the encryption:

$success = openssl_pkcs7_encrypt(
    $tempBodyFile,
    $tempEncfFile,
    $pubkey,
    $headers,
    PKCS7_TEXT,
    1
);

if (!$success) {
    throw new Exception('mail encryption error');
}

The PKCS7_TEXT flag is important.

After the encryption, we read the encrypted content and separate the mail header and body string.

$data = file_get_contents($tempEncfFile);

// separate header and body, to use with mail function
[$header, $body] = explode("\n\n", $data, 2);

Finish. We can send the mail:

mail($headers['To'], $headers['Subject'], $body, $header);

send encrypted mails over SMTP using PHPMailer

The PHPMailer has no support for encrypted mail.
Also, there is no function to send Mails with raw header and body text.

Here is a simple extension to send smtp-mails with raw message data:

class CustomMailer extends PHPMailer
{

    public function sendSmtpSend(string $header, string $body)
    {
        return $this->smtpSend($header, $body);
    }
}

We use the internal smtpSend method, so we have to set a recipient and the from-address for the communication in the SMTP protocol.

$phpmailer = new CustomMailer();
$phpmailer->SMTPDebug = 0;
$phpmailer->isSMTP();
$phpmailer->Host = '--insert--';
$phpmailer->SMTPAuth = true;
$phpmailer->Username = '--insert--';
$phpmailer->Password ='--insert--';
$phpmailer->SMTPSecure = '--insert--';
$phpmailer->Port = '--insert--';

$phpmailer->setFrom($headers["From"]);
$phpmailer->addAddress($headers["To"]);
$mailSend = $phpmailer->sendSmtpSend($header, $body);

if ($mailSend) {
    echo 'OK';
} else {
    echo 'FAIL';
}

send html mail

Replace the PKCS7_TEXT flag in the openssl_pkcs7_encrypt function call with a 0.
Start your message body with a content type header:

 $message = "Content-Type: text/html; charset=utf-8: 1.0\r\n\r\n";

source

❰ back