AspEmail Manual Chapter 5: Authentication & Security

Contents

5.1 SMTP Authentication

SMTP servers are often configured to require an email client to provide a username and password when sending a message. This is done to protect the SMTP server from unauthorized use by external users, and to prevent spam.

An attempt to send email via a secured SMTP server may result in run-time errors such as

550 Relaying Denied

The SMTP protocol provides several authentication methods through which a mail client submits its security credentials to the server during an SMTP session. SMTP servers usually support at least one authentication method, but most support several.

The most common SMTP authentication methods are as follows:

1. AUTH=LOGIN

This is the simplest authentication method where the username and password are sent to the SMTP server in clear text (that is, unencrypted) although the values are Base64-encoded. Authentication parameters can therefore be intercepted.

2. CRAM-MD5

The server sends a random string to the client. Both the client and the server calculate an MD5 digest of the concatenation of the random string and the password; the client then sends the server the result of its calculation. The server compares the two results.

This method is more secure than AUTH=LOGIN because the actual password never gets sent to the server.

2. NTLM

This is Microsoft's proprietary authentication protocol also known as "Challenge/Response". It is also secure in the sense that the password never gets transmitted over the network.

5.2 AspEmail's Authentication Support

AspEmail provides two properties, Username and Password through which user credentials are specified.

<%
...
Mail.Username = "Administrator"
Mail.Password = "He11o@World!"
...
Mail.Send
%>

When used in the standard mode (message queuing is not used), AspEmail supports the AUTH=LOGIN method only. When sending queued mail, AspEmail, in conjunction with EmailAgent, supports all three protocols described above. When attempting to negotiate an authentication protocol with the SMTP server, AspEmail tries the authentication methods in the following order: CRAM-MD5, NTLM, AUTH=LOGIN.

As of Version 5.5.0.1, AspEmail also supports the SASL (Simple Authentication and Security Layer) XOAUTH2 authentication mechanism. Under this mechanism, an oAuth 2.0 access token is passed via Mail.Password property instead of the account password. The access token must be prepended by the string "[oauth]" (case is immaterial), as follows:

<%
...
Mail.Username = "myaccount@gmail.com"
Mail.Password = "[oauth]ya29.Il-8B-88n..............KtBS-ZEQOAZ9tTWg"
...
Mail.Send
%>

AspEmail's oAuth 2.0 support is described in Section 5.6 below.

5.3 Secure Mail Support

When used in conjunction with Persits Software AspEncrypt, AspEmail is capable of sending signed and/or encrypted messages in the industry-standard S/MIME format.

When sending an encrypted (enveloped) message, the AspEmail/AspEncrypt tandem takes the recipient's digital certificate and encrypts the message with its public key. Only the owner of the certificate can decrypt such a message since no one else has the corresponding private key.

When sending a digitally signed message, the sender certificate's private key is used to sign the message. AspEmail/AspEncrypt are also capable of sending messages that are first signed and then encrypted.

S/MIME-Compliant AspEmail is the only ASP component on the market that is officially certified to be S/MIME-enabled by RSA Security, the inventor of public-key cryptography and S/MIME, and was listed on RSA's web site among other S/MIME-enabled software products (the list is no longer the RSA web site.)

To learn how to send secure mail with AspEmail/AspEncrypt, read the Secure Mail chapter on the AspEncrypt.com web site.

5.4 Transport Layer Security (TLS) Support

5.4.1 TLS (Ports 25 and 587)

As of Version 5.1, AspEmail supports the Transport Layer Security (TLS) protocol. This secure protocol encrypts all traffic between the email-sending client application and SMTP server, and not just the passwords. The security of the protocol is based on public-key cryptography.

Some SMTP servers require the email sender to use TLS. An example of such a server is Google's popular free smtp.gmail.com server. An attempt to use this SMTP server without TLS results in the error message

530 5.7.0 Must issue a STARTTLS command first.

To enable AspEmail's TLS support, you must set the TLS property to True, as follows:

Mail.Host = "smtp.gmail.com"
Mail.Username = "MyGMailAccount"
Mail.Password = "He11o@World!"
Mail.TLS = True
...
Mail.Send

Some SMTP servers requiring TLS run on port 587 as opposed to the default SMTP port 25. If that is the case, the port number needs to be specified as well:

...
Mail.TLS = True
Mail.Port = 587
...

5.4.2 SSL (Port 465)

When the Mail.TLS property is set to True as described above, AspEmail begins an SMTP session via an unsecured channel. It receives an SMTP server greeting, issues the EHLO command followed by the STARTTLS command, and then initiates a secure key exchange procedure known as a "handshake". Once the handshake is completed, all further communications between AspEmail and the SMTP server are encrypted.

Some SMTP servers support a slightly different secure process often referred to as SSL (Secure Socket Layer). Under SSL, the client initiates the handshake procedure immediately after connecting to the SMTP server (usually on port 465), and every single SMTP communication including the greeting and EHLO command is transmitted via a secure channel from the start. Under SSL, the underlying secure protocol is exactly the same as under TLS, it just kicks in at the very beginning of the SMTP session instead of in the middle of it.

As of Version 5.4, AspEmail supports the SSL protocol. To enable it, the Mail.SSL property must be set to True, and Mail.Port to 465, as follows:

...
Mail.SSL = True
Mail.Port = 465
...

Note that TLS/SSL is currently only supported by AspEmail itself but not EmailAgent. However, it is supported by EmailAgent.NET.

5.4.3 TLS 1.2 Support

Version 1.0 of the Transport Layer Security protocol (TLS 1.0) relies heavily on the MD5 hash algorithm, which has been cracked and is currently considered insecure. It contains other vulnerabilities as well. TLS 1.0 will therefore soon be deprecated.

As of AspEmail 5.5, whenever the Mail.TLS or Mail.SSL property is set to True, AspEmail by default uses TLS 1.2, a more secure protocol which is based on SHA256 and 128-bit and 256-bit AES. To force AspEmail 5.5+ to use TLS 1.0, the new property Mail.TLSVersion must be set to "1.0", as follows:

...
Mail.TLS = True
Mail.TLSVersion = "1.0"
...

The TLSVersion property currently supports two string values: "1.0" and "1.2".

5.4.4 Cipher Suites

A cipher suite is a combination of various cryptographic algorithms working together to carry out a TLS session. These algorithms include a public-key cipher for key exchange (such as RSA or Diffe-Hellman), a symmetric cipher for data encryption (such as 3DES or AES), one or more one-way hash functions for key generation and message authentication, such as SHA1/MD5 or SHA256, and in some cases a digital signature algorithm.

AspEmail currently supports the following cipher suites:

TLS Version
Code
Name
1.0
0004
TLS_RSA_WITH_RC4_128_MD5
1.0
000A
TLS_RSA_WITH_3DES_EDE_CBC_SHA
1.0
002F
TLS_RSA_WITH_AES_128_CBC_SHA
1.0
0035
TLS_RSA_WITH_AES_256_CBC_SHA
1.2
002F
TLS_RSA_WITH_AES_128_CBC_SHA
1.2
003D
TLS_RSA_WITH_AES_256_CBC_SHA256
1.2
C027
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
1.2
009C
TLS_RSA_WITH_AES_128_GCM_SHA256
1.2
C02F
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

The cipher suites 009C and C02F based on the Galois/Counter Mode (GCM) are available as of Version 5.6.0.3. Also, as of this version, the cipher suite chosen by the SMTP server during the last successful TLS session can be retrieved via the TLSVersion property. The value returned by this property is in the format "1.2; Cipher Suite C02F" where the prefix such as 1.2 is the TLS version and the hexadecimal number such as C02F is the cipher suite code (see the table above.)

5.5 DKIM Support

DomainKeys Identified Mail, or DKIM, is a method by which the sender of email digitally signs the message to prove it really came from the domain that is claims it came from. The signature includes some or all message headers including, most notably, the From: header which is often forged by spammers. The message body is also included in the signature to prove it has not been altered.

The DKIM signature is included in the message as a regular header, for example:

From: <sales@persits.com>
To: some@somecompany.com
Subject: Testing DKIM
Date: Thu, 26 Apr 2012 14:19:01 -0400
Message-ID: <16901082.67252.133546436>
DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple;
   d=persits.com; s=nyc;
   h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type;
   bh=B9iLqMScsZGmBPHOc7tnsDJwRx0=;
   b=VkyPlX4z6IWwmZj2qKehHF5w9+Amzf4baaVji6tHDJ1Al8Fhxxb7aBdrLv1vVxdm
      vzyh1ZxGGUXln+iF0K12XR1aCC143LABg5ATd7ksEdJn8NtMTq6ajRzl95t0rTsB
      QMKaTvaWjQgIJ6GRwk7em0CI6nAE2o6tuOgxx5boBBI=

MIME-Version: 1.0
...

The message recipient verifies the signature by obtaining the signer's public key from the DNS records of the domain the message claims it came from. Unlike the S/MIME standard mentioned above, DKIM does not use certificates but "raw" public keys for message verification.

One or multiple keys can be associated with a particular domain. Each key is assigned a unique name, or selector. In the example above, the sender domain is persits.com and selector is nyc. The public key to verify the signature has to be put in the DNS record of the type TXT for the domain nyc._domainkey.persits.com.

For more information about DKIM, see www.dkim.org.

5.5.2 Getting Ready to Send DKIM-Enabled Messages

Bofore you can start sending messages equipped with DKIM signatures using AspEmail or AspEmail.NET, the following steps must be taken:

  1. Obtain a personal certificate.

    Certificates are a convenient mechanism for obtaining, storing and distributing public/private keys needed for DKIM signing and verification, and our products' API relies on them. Since DKIM does not use certificates themselves, it is not important where you obtain your certificate. We recommend creating a self-signed certificate. The following KB article explains how to do it on Windows 10:

    If you need multiple keys, obtain a separate certificate for each key. Export the certificates from IE to files both with and without their private keys (file extension .pfx and .cer, respectively.)

  2. Create DNS TXT records for each key.

    For example, for the domain mycompany.com and selector hq, you must create a DNS record of the type TXT for the domain

    hq._domainkey.mycompany.com

    The value for this TXT record must contain the base64-encoded public key of your certificate in the form

    k=rsa; p=MIIBIjANBgkqhkiG9.....NVdiQqQBewIDAQAB;

    You can obtain the public key for your certificate programmatically using AspEncrypt's CryptoCert.PublicKeyInfo property (AspEncrypt 2.7+ is required,) but for your convenience we have set up an online application which enables you to upload your .cer file to our server and obtain the value for your TXT record instantly:

    Verify the validity of your DNS record via the following online tool (warning: the link below is not a Persits Software page):

5.5.3 AspEmail's DKIM Support

Once the DKIM infrastructure has been set up, you are ready to send email equipped with DKIM signatures. As of Version 5.3, AspEmail offers the SendCertified method which expects 4 required and 1 optional arguments: the signer certificate, domain, selector, option flags, and optionally the message queue path.

  • The signer certificate argument is an instance of AspEncrypt's CryptoCert object. It can be obtained either from a .pfx file or directly from a certificate store. For more information about using certificates for signing purposes, see Section 5.4 of the AspEncrypt user manual.
  • The domain and selector arguments are two strings specifying the domain and selector (such as "mycompany.com" and "hq" in the example above.) The message recipient uses this information to obtain the public key for signature verification from the domain's DNS records. Note that the domain must match the domain of the email address specified via the Mail.From property.
  • The option flags argument is a collection of flags and should normally be 0. Currently, only two flags are defined. Bit 1, if set, prevents the Date header from being included in the signature, bit 2, if set, prevents the Message-ID header from being included in the signature. As of Version 5.6.0.4, Bits 3, 4 and 5 prevent the custom headers List-Unsubscribe, List-Unsubscribe-Post, and Feedback-ID, respectively, from being included in the signature.
  • The last optional argument is only used when message queing is enabled and has the same purpose as the optional Path argument to the Send method.

The integrity of a DKIM signature relies on the message headers and body being in a standard (or "canonicalized") form. To ensure the body is properly formatted, you must set the property ContentTransferEncoding to "Quoted-Printable" before calling SendCertified. If necessary, also use the method EncodeHeader for the headers such as Subject and others.

The following code sample sends a DKIM-signed message:

' Obtain signer certificate from pfx file
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Store = CM.OpenStoreFromPFX("c:\path\cert.pfx", "password")
Set Cert = Store.Certificates(1)

' change to address of your own SMTP server
strHost = "smtp.myisp.net"

Set Mail = Server.CreateObject("Persits.MailSender")
Mail.Host = strHost
Mail.From = "info@mycompany.com"
Mail.AddAddress "someone@anothercompany.com"
Mail.Subject = "Thank-you for your business"
Mail.Body = "Message body"
Mail.ContentTransferEncoding = "Quoted-Printable" ' Required

' Domain must match Mail.From address
Mail.SendCertified Cert, "mycompany.com", "hq", 0

5.6 Google GMAIL oAuth Support

5.6.1 What is oAuth?

OAuth is an open-standard authorization protocol that describes how unrelated servers and services can safely allow authenticated access to their assets without actually sharing the account password. A typical example of oAuth at work is when you are asked to login to a web site using your Google or Facebook account to share your profile name and picture.

In the context of AspEmail and a third-party mail provider such as Google GMAIL, oAuth provides a mechanism for AspEmail to send email on behalf of a GMAIL user without specifying the GMAIL account password in the script. Instead, an access token obtained from Google is specified via the Password property, and the token value must be prepended with the string "[oauth]" (this prefix is case-insensitive), as follows:

<%
...
Mail.Host = "smtp.gmail.com"
Mail.TLS = True
Mail.Username = "myaccount@gmail.com"
Mail.Password = "[oauth]ya29.Il-8B-88nf.......GhoNhUXKtBS-ZEQOAZ9tTWg"
...
Mail.Send
%>

If you are using message queuing with EmailAgent.NET (described in Chapter 4 of the AspEmail.NET Manual), the access token needs to be put in the password boxes of the EmailAgent.NET Configuration Panel on both the SMTP and POP3 tabs.

As of February 2020, it is still possible to use AspEmail to send email via Google's smtp.gmail.com server the old-fashioned way, by specifying the Google account's username and password in your script. The Google account needs to have the "Allow less secure apps" option enabled for this to work.

However, Google has clearly signaled its intention to disallow "less secure" applications (that is, those not using oAuth) to access its mail server. In response to that, we have added oAuth support to AspEmail 5.5.0.1, and provided a way to obtain access tokens from Google both interactively and programmatically.

5.6.2 How to connect to GMAIL via oAuth?

The first step is allow AspEmail access to your GMAIL account by going to the the followig URL:

If you have multiple Google accounts, you will be asked to pick one and sign in. Ignore the "This app isn't verified" warning.

You will be presented with the following dialog:

When you click Allow, you will be asked to confirm your choice, and after that, you will be given a code that looks something like this:

4/wQGBh0Mg9wcDj1DESm2pBlF1VdKjzsE1IvioO8X65_J22YHGi2fLtcM

This authorization code needs to be exchanged for the actual access token. The exchange can be performed both interactively and programmatically.

IMPORTANT: An authorization token can only be used once. After it has been exchanged for the access token, it cannot be used again.

To obtain your access token interactively, go to https://www.aspemail.com/oauth.aspx.

There are two tabs, Access Token and Refresh Token. On the Access Token tab, you can exchange your authorization code for an access token which you can use right away, as well as a refresh token, which should be saved. The refresh token can later be used on the Refresh Token tab to obtain a new access token once the current one expires. Access tokens usually expire in an hour (3600 seconds).

An access token is a long string that look something like this:

ya29.Il-8B-88nfQ3RIutXihR.....ykaefuyMabxAxpGhoNhUXKtBS-ZEQOAZ9tTWg

and a refresh token like this:

1//0dtDFz5F3t_2XCgYIARAAGA0SNwF....6bxr0dWSkMdsM5V2aEqepf_E8Y1UHVKc

To obtain your access token programmatically, use AspEmail's method GetAccessToken. This method expects the following input arguments: the service name (currently, only "GMAIL" is supported), the authorization code or refresh token, and a Boolean flag indicating whether the 2nd argument is an authorization code (if set to False) or a refresh token (if set to True). The method returns a new instance of the MailSender object with the property Username set to the access token, Password to the refresh token (if applicable), and Timeout to the expiration time in seconds.

For example:

<%
Set Mail = Server.CreateObject("Persits.MailSender")
' Get access and refresh tokens from authorization code
Set Mail2 = Mail.GetAccessToken("GMAIL", "4/wQGBh0....HGi2fLtcM", False)
AccessToken = Mail2.Username;
RefreshToken = Mail2.Password
ExpiresIn = Mail2.Timeout
...
%>

The following script obtains a new access token from the refresh token obtained via the previous script:

<%
Set Mail = Server.CreateObject("Persits.MailSender")
' Get new access token from refresh token
Set Mail2 = Mail.GetAccessToken("GMAIL", "1//0dtDFz...1UHVKc", True)
AccessToken = Mail2.Username;
ExpiresIn = Mail2.Timeout
...
%>

5.6.3 AspEmail's API Mode

As of June 2022, Google has stopped supporting "less secure applications" and blocked the use of the SMTP protocol to applications with the sensitive scope (which is a set of permissions granted to the application by Google itself). For those applications to send email via GMAIL, they must now use Google API instead of the traditional SMTP protocol. When an API (such as Google API) is used, an application posts data via the HTTPS protocol to a particular URL (known as an endpoint) in JSON format, and receives a response from that URL also as a JSON string.

As of Version 5.6.0.2, AspEmail supports the API mode, under which the body of the message is POSTed to Google in a single large HTTPS post. To enable the API mode, the Mail.Host property must be set to "Google API". The access token is specified via the Mail.Password property. There is no need to specify the TLS, SSL or Port properties.

Google access tokens expire every hour and need to be renewed regularly. It is up to the application developer to implement a mechanism to renew the access token via the refresh token automatically when needed. The refresh token, current access token, and its expiration information can be stored in a file, system registry, database, or some other way. The following code sample uses an ASCII file by the name of token.txt located in the same folder as the script, to store the refresh token, access toke, and expiration date as three lines of text.

The file needs to be initialized with a refresh token obtained manually via the Access Token Center as shown in the previous section. The script looks for an access token and expiration information in the file. If not found, or if the current time exceeds the expiration time, the script obtains a new access token via the GetAccessToken method, and updates the file. The script then sends email with AspEmail and uses the access token as the password:

<%
Option Explicit

Dim token_filename
Const Read = 1
Dim HelperObj, TokenObj
Dim FSO, file, data, Lines, i
Dim AccessToken, RefreshToken, ExpDate

token_filename = Server.MapPath("token.txt")

Set FSO = server.createObject("Scripting.FileSystemObject")

Set file = FSO.OpenTextFile(token_filename, Read, False, False)
data = file.ReadAll
file.Close

' Refresh tokens contain ".", Access tokens "//" and dates ":"
Lines = Split(data, vbCrLf)
For i = 0 To Ubound(Lines)
   If Instr( Lines(i), "//" ) > 0 Then
      RefreshToken = Lines(i)
   Elseif Instr( Lines(i), ".") > 0 Then
      AccessToken = Lines(i)
   Elseif Instr( Lines(i), ":") > 0 Then
      ExpDate = Lines(i)
   End If
Next

If RefreshToken = "" Then
   Response.Write "Refresh token not found."
   Response.End
End If

if ExpDate = "" Then ExpDate = "1/1/1900"

' Expiration info missing, or token expired? Get a new one, save it
if Now() >= CDate(ExpDate) Then
   Set HelperObj = Server.CreateObject("Persits.MailSender")
   Set TokenObj = HelperObj.GetAccessToken("gmail", RefreshToken, true)

   AccessToken = TokenObj.Username
   ExpDate = Now() + TokenObj.Timeout / 86400 ' # if seconds per day

   ' Save new info
   Set file = FSO.CreateTextFile(token_filename)
   file.WriteLine RefreshToken
   file.WriteLine AccessToken
   file.WriteLine ExpDate
   file.Close
End If

' Send email via AspEmail. Use AccessToken as the password.
Dim Mail
Set Mail = Server.CreateObject("Persits.MailSender")
Mail.Host = "Google API" ' API mode
Mail.Username = "<gmail address>"
Mail.Password = AccessToken
Mail.From = Mail.Username
Mail.AddAddress "email@domain.com"
Mail.Subject = "Email subject"
Mail.Body = "Email body"
Mail.Send
%>