Mail Login
Extend
assignment 2 to log in to request TLS and
log in to the server. Here's what mine looks like:
[bennet@bennet smtp]$ ./smlog1 smtp.gmail.com @gmailsmlog1
S: 220 smtp.gmail.com ESMTP h11-20020a81b64b000000b00607f8df2097sm60317ywk.104 - gsmtp
C: EHLO 10.27.2.212
S: 250-smtp.gmail.com at your service, [167.160.210.1]
S: 250-SIZE 35882577
S: 250-8BITMIME
S: 250-STARTTLS
S: 250-ENHANCEDSTATUSCODES
S: 250-PIPELINING
S: 250-CHUNKING
S: 250 SMTPUTF8
C: STARTTLS
S: 220 2.0.0 Ready to start TLS
C: EHLO 10.27.2.212
S: 250-smtp.gmail.com at your service, [167.160.210.1]
S: 250-SIZE 35882577
S: 250-8BITMIME
S: 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
S: 250-ENHANCEDSTATUSCODES
S: 250-PIPELINING
S: 250-CHUNKING
S: 250 SMTPUTF8
C: AUTH PLAIN MCSZ8aIzMHAEbyDK3kfDm92/xepJCelJp4B0zatI
S: 235 2.7.0 Accepted
C: HELP
S: 214 2.0.0 https://www.google.com/search?btnI&q=RFC+5321 h11-20020a81b64b000000b00607f8df2097sm60317ywk.104 - gsmtp
C: QUIT
S: 221 2.0.0 closing connection h11-20020a81b64b000000b00607f8df2097sm60317ywk.104 - gsmtp
Additional Protocol Steps
You will need to add only a few things to your assignment 2 solution.
- Add a TLS layer to your socket, after connection and before adding
the buffering layer. The
web page
downloader will show you how to do it, except send false as the
third parameter, instead of the secure flag as the example does.
- After sending EHLO and receiving the response, send the
STARTTLS command as you see above. After receving a positive
response, run the start_tls() method the TLS layer object you
created earlier (with false to keep TLS actually turned off).
It will perform the TLS handshake with the server.
- Now, send EHLO again. The protocol requires this, since
the list of optional features will change. In fact, if you look at the
log above, you will see that STARTTLS is gone (can't start it
when it's alreayd going), and various AUTH LOGIN options
have appeared. (You can't log on until the connection is secure).
- Send the AUTH PLAIN as you see above. The string
contains the the account and password encoded in base-64. More on that
in a moment.
- Then, as before, send the help command and quit. If the server
sends you an error, immediately send quit and disconnect. Log everything,
as shown.
Other Changes
To accomplish login, you need to tell the program what account and password
to use. You need to change the command line scanning to allow the program
to be run in either of two ways:
programname hostname accountname password [ port ]
programname hostname @credfile [ port ]
In the second form,
credfile is the name of a plain
text file containing exactly two lines: the account name on the first,
and the password on the second. This form mostly just keeps the
password off the command line. Your program should open this file and
read of the two lines to get the credentials. In either form,
if anything is missing, or if a credential file cannot be read, just
print a message and exit.
Supposedly Simple Auth
The string sent with the AUTH PLAIN command
is built from three parts separated by zero bytes: An “authorization
identity,” which is usually empty (and will
always be for us), an account, and a password. This
string is then encoded using base-64, which allows sending the zeros and
other non-plain-ascii characters in the account or password. To
simplify things, I'm passing along
some code which will
create this string for you. Send it the account and password, and
it concatenates the strings and does the base-64 encoding.
There are plenty of libraries that can encode base-64, but I thought
it was less trouble to just code it than create an additional
library dependence for the project. You can
just copy this into your program, or store it in its own
.cpp file and
compile the file separately
and link together. (For separate compilation, you will need to add
#include <string> to the the authstring file, and add
add the line
string authstring(string acct, string passwd);
to the main.)
An Account
You will probably not want to try this with your real email account, but
create a throw-away free account for testing.
The above example shows good ol'
Gmail.
There are other free
email accounts, but for many access outside the web interface is
not a free feature. To use Gmail, you will need to
create an
app
password, so you have a bit of joyful form-filling before you. The app
password is just a randomly-generated password used
to log in to the mail server. Google won't let you use the same password as
the one for the web site. And when I went to create one, I could not
find the the “App passwords” link
described in the instructions, but the search box on the page
found the control for me.
I tried to use an outlook mailbox, but it does not accept auth plain.
It uses XOUTH2, which i don't know much about, and have not tried to
implement. The one other I was able to successfully use is
GMX. For that one, after
creating your account, you need to enable the remote connection. From
the browser email box, choose “More” from the link index at the top,
and go to E-mail settings / pop/imap, and enable pop/imap access. The
SMTP server name is shown there, the account is just your full email address,
and password the same one you log in to the web site with.
I used standard mail submission port, 587.
Using the EHLO Response
Note that both STARTTLS and AUTH PLAIN are
optional features of SMTP. The response from EHLO tells if they
are supported. I've written mine to just try, and let the server
respond with an error if it doesn't work. That's sort of
fast-and-loose, but also easier. It allows a more sophisticated
client to adapt to the capabilities of the server.
Submission
When your program is working, nicely commented and properly indented,
submit it using the form
here