Postfix SMTP – Troubleshooting STARTTLS Not Working Properly

postfix

When I use PHPMailer to send mail through Postfix, I use the default config with these modifications:

# SMTP from other servers to yours
smtpd_tls_key_file = /etc/postfix/myletsencryptcert.key
smtpd_tls_cert_file = /etc/postfix/myletsencryptcert.crt
smtpd_tls_CAfile = /etc/postfix/myletsencryptcert.crt
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3
smtpd_tls_protocols=!SSLv2,!SSLv3
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database =
    btree:/var/lib/postfix/smtpd_tls_session_cache

When I use this config, and run PHPMailer, it says connection failed, right after making the STARTTLS command. My PHPMailer config is

$mail = new PHPMailer(true);

    $mail->isSMTP();
    $mail->Host       = 'localhost';
    //$mail->SMTPAuth   = true;
    $mail->Username   = 'noreply@example.com';
    //$mail->Password   = 'passwordwhichissecretobviously';
    $mail->SMTPSecure = 'tls';
    $mail->Port       = 25;
    $mail->SMTPAutoTLS = false;

    $mail->setFrom("noreply@example.com", "Some person");
    $mail->addAddress("sperson@example.com");
    
    $mail->isHTML(true);
    $mail->Subject = "Web Development";
    $mail->Body    = "
Some random HTML message
";
    $mail->AltBody = "some normal message without HTML";
    $mail->XMailer    = "0"; 
    $mail->CharSet = 'UTF-8';
    $mail->Encoding = 'base64';
    
    $mail->DKIM_domain = 'example.com';
    $mail->DKIM_private = '/right/path/to/dkimkey/which/works/properly/dkim.key';
    $mail->DKIM_selector = 'default';
    $mail->DKIM_passphrase = '';
    $mail->DKIM_identity = $mail->From;
    $mail->DKIM_copyHeaderFields = false;

And even if I use telnet and do it, I get after running the STARTTLS command.

I found out that using this allows me to send the mail with PHPMailer:

$mail->SMTPOptions = array(
    'ssl' => array(
        'verify_peer_name' => false
    )
);

But I think that would be a security issue. How else can I make this work?

Best Answer

Peer name verification only works if the peer name is known.

Make it known, by configuring the server name as the Host.

// this is a name not mentioned in the cert
$mail->Host       = 'localhost';
// better: a full domain name
$mail->Host       = 'mx8.mydomain.example';

You (should) have a certificate for the name of your mail server - comparing that name in the certificate to localhost is not sufficient to determine the certificate is appropriate. Any mail client or test tool that wants to verify your certificate needs to know the name it should be comparing against.

Nitpick: Your SMTPSecure value contains the value of the const variable (the string "tls") - use the name (PHPMailer::ENCRYPTION_STARTTLS) because the value itself does not explain what it means without looking into the documentation.

About telnet: Using a simple test tool like telnet is a good choice for figuring out issues - but you cannot use telnet here - this program is (typically) not aware of TLS encryption. I like to use a utility included with openssl instead:

openssl s_client -connect hostname:25 -starttls smtp

(yes, it can even spell out STARTTLS for you and displays the connection parameters in a somewhat human-readable fashion)