Hi there,
I have been trying to solve a SMTP authentication issue for a few days now. One reason for the “a few days” is the lack of or just plain wrong information we got from the service provider.
The other reason was the lack of useful logging on the server we tried to connect with the mailserver.
In the early times, we used simple telnet to connect to port 25 without any encryption. This made testing the whole process very easy. But that’s not really an option anymore, with encryption being mandatory everywhere.
So today I want to show a few ways, we can test SMTP authentication, even with STARTTLS/TLS enabled.
Let’s begin.
Windows Powershell (Send-MailKitMessage)
First, let me show the powershell way, if you want to verify the connection on a Windows Server.
We need to install a powershell module first, since Send-MailMessage has been marked as deprecated by Microsoft since 2020.
# Install the Send-MailKitMessage Module
PS C:\> Install-Module -Name Send-MailKitMessage
# Send a test mail using `Send-MailKitMessage`
PS C:\> Send-MailKitMessage -SMTPServer "<mailserver>" -Port 587 -From "<surname.name@example.local>" -RecipientList "<recipient@otherdomain.local>" -Subject "test" -TextBody "SMTP Test" -Credential (Get-Credential) -UseSecureConnectionIfAvailable
There is no output if the message got sent but if you have an error, it should show something like this.
send-mailkitmessage : 535: 5.7.3 Authentication unsuccessful
If you just want to check if the port is reachable at all, use Test-NetConnection.
PS C:\> Test-NetConnection -ComputerName <mailserver> -Port 587
ComputerName : mailserver
RemoteAddress : 192.168.200.2
RemotePort : 587
InterfaceAlias : Ethernet0
SourceAddress : 192.168.200.3
TcpTestSucceeded : True
Linux (swaks)
On Linux we have a tool I somehow hadn’t come across before despite it being well known. swaks.
It’s a command-line tool specifically designed for SMTP testing and debugging.
The syntax is very similar.
# First we need to install it. (I am using Fedora 44 for this)
$ sudo dnf install swaks -y
# Now we can test the connection. You can also remove the `--auth-password`, it will ask you for the password after executing.
# If you are using TLS rather than STARTTLS, use --tls-on-connect instead of --tls
$ swaks --server <mailserver> --from <surname.name@example.local> --to <recipient@otherdomain.local> --auth --auth-user <surname.name@example.local> --auth-password <secret-password> --port 587 --tls
The openssl way
This method uses openssl to connect to the mail server. This feels very similar to the old telnet approach, though I found it less reliable. Let me show it anyway.
The syntax is the same on Windows and Linux.
## In this example I am using AUTH LOGIN. Note that base64 is encoding, not encryption — always use this over a TLS connection.
## First we need the username and password in base64.
# Linux
$ echo -ne "username" | base64
<some-random-base64-username>
$ echo -ne "password" | base64
<some-random-base64-password>
# Windows
PS C:\> [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("username"))
<some-random-base64-username>
PS C:\> [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("password"))
<some-random-base64-password>
# Connecting to mailserver using openssl (we don't need `-crlf` and `ign_eof` on windows)
$ openssl s_client -connect smtp.example.com:587 -starttls smtp -crlf -ign_eof
... a lot of text...
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Protocol: TLSv1.2
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 151300002EF0114F22DBE29....A733B7FC4222F463FBE79A
Session-ID-ctx:
Master-Key: 52C80385CFA1574E52218C07F6E4F9....1F5F1964D19F67A2EE5A8D88889F7AD60
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1778502688
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: yes
---
250 SMTPUTF8
# Type the EHLO
EHLO hostname.example.local
250-mailserver Hello [192.168.200.2]
250-SIZE 37748736
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-AUTH LOGIN
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250 SMTPUTF8
# Type in the auth type AUTH LOGIN
AUTH LOGIN
334 VXNlcm5hbWU6
# Your base64 username
<some-random-base64-username>
334 UGFzc3dvcmQ6
# Your base64 password
<some-random-base64-password>
235 2.7.0 Authentication successful
# Type MAIL FROM and the email sender
MAIL FROM:surname.name@example.local
250 2.1.0 Sender OK
# Type RCPT TO and the recipient
RCPT TO:recipient@otherdomain.local
250 2.1.5 Recipient OK
# Type in `DATA` and the rest of the required information in the format as seen below. To send the mail, type `.` in a new line.
DATA
354 Start mail input; end with <CRLF>.<CRLF>
Subject: Test E-Mail
From: surname.name@example.local
To: recipient@otherdomain.local
This is the body.
.
# Mail was sent.
250 2.6.0 <b4e2ca2a-3205-4f45-971f-4bfg8sfe33bd@mailserver.example.local> [InternalId=3423452232927, Hostname=mailserver.example.local] 1391 bytes in 41.288, 0,033 KB/sec Queued mail for delivery
That’s it. You should receive an e-mail if everything worked correctly.
Exchange Logs
What if we want to check the logs on the Exchange Server?
We are using Windows Server SE, so no cloud solution.
First, we log into the ECP “https://mail.server.local/ecp".
Navigate to “mail flow” -> “receive connector” and select one of the connectors you want to enable logging for. Here we click on “Logging - on” in the right panel, to enable logging.
Once that’s done, we can open a powershell window and navigate to the SmtpReceive folder.
Here you will find a lot of files, if you have been running the logging for a while. To find anything useful, I usually run the Select-String command.
# The path depends on your installation.
PS C:\> cd "C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd\ProtocolLog\SmtpReceive"
# Find logs based on IP
PS C:\> Select-String -Path .\*.LOG -Pattern "192.168.200.100"
# Find logs based on mail
PS C:\> Select-String -Path .\*.LOG -Pattern "surname.name@example.local"
That’s it.
Hope this helps.
Until next time.
Comments