Lab 1: Charlie on the MTA
Due: 12:30pm, Tuesday, April 6th, 2010
Your task for this assignment is to write a simple Mail Transfer Agent
(MTA). An MTA is a program that relays email messages between
senders, receivers, and possibly other MTAs. MTAs are the servers
that process email messages in the Internet, passing them from the
sender's email client---or Mail User Agent (MUA)---and the receiver's
mail delivery agent. By far the most common MTA in use on the
Internet is the infamous sendmail program. Most of
sendmail's notoriety comes from its incredible complexity and
resulting never-ending discovery of security vulnerabilities. Don't
despair; your MTA will be considerably simpler, although not
necessarily any easier to debug!
The reason you're writing an MTA is not to build a replacement for
sendmail (although the Internet could badly use one!), but rather to
learn about how complex Internet servers are constructed. Initially,
we'll start off simple with a single-threaded server that can only
process one mail message at a time. It should be able to accept a
mail message from a MUA, forward the message on to its destination,
and then prepare to accept the next mail message. We'll fix this
limitation as part of Lab 2.
Your MTA will use the Internet-standard Simple Mail Transfer Protocol
(SMTP) to exchange mail messages. SMTP is documented in RFC 2821,
but you'll only need to implement a small subset of the commands
listed below. You will not need to handle local delivery of mail
messages. Instead, your MTA will only forward email messages on to
another MTA for actual delivery.
You are responsible for the following requirements:
You do not need to bother with the following things. You should just
ignore them as best you can.
- Your MTA is able to properly receive a message from a
well-behaved MUA like Netscape, Outlook Express, or Mozilla. This
will require you to support the following SMTP commands: HELO, MAIL,
DATA, RCPT, QUIT, and RSET.
- You may not use the fork() system call.
- You do not need to handle messages with more than 255
- You do not need to handle mail messages larger than 65535
If you are able to send a simple email message using your MTA, you're
in good shape.
- You don't need to support local destinations or source-routed
messages. If the argument to the RCPT TO: command is not of the form
firstname.lastname@example.org, you should refuse to accept the message.
- You don't need to support the use of dotted-quad IP addresses
instead of domain names.
- You don't need to queue messages that cannot be delivered. Any
destination address that is unable to accept the message immediately
(after trying all the MX options--see below) should be treated as a
delivery failure, and an "undeliverable mail" notification should be
returned to the sender immediately.
- Any other SMTP commands like EXPN, VRFY, HELP, ETRN, NOOP, or
VERB. You may simply return an error message if your MTA receives one
of these commands.
- ESMTP extensions. You do not need to recognize EHLO or any of the
additional parameters to standard SMTP commands.
- You do not need to implement the data transparency procedure
described in Section 4.5.2 of the RFC. Basically, you can assume your
MTA will never receive a message with a period as the first character of a
- You should ignore all headers in the DATA portion of the message.
Further, you do not need to implement any sort of loop detection.
A sample mail transaction
SMTP is a simple client/server protocol that runs over TCP. A client
(either an MUA or an MTA) opens a TCP connection to an MTA, identifies
itself, specifies the recipients of the message, sends the contents
of the message, and quits. The server processes the message and
forwards it on to the destinations specified using the same procedure.
You can play with a real, live MTA yourself. The UCSD campus has an
MTA running on smtp.ucsd.edu.
% telnet smtp.ucsd.edu 25
This opens a TCP connection to port 25 (the well-known SMTP port) on
smtp.ucsd.edu. You should see:
Connected to smtp.ucsd.edu.
Escape character is '^]'.
220 smtp.ucsd.edu ESMTP Sendmail 8.13.6/8.13.6; Fri, 26 Mar 2010 11:22:21 -0700 (PDT)
The first three lines are output from the telnet program. The last is
the greeting sent by the MTA (Sendmail, surprise, surprise) at
You can then identify yourself using the HELO command:
and the MTA returns
250 smtp.ucsd.edu Hello usher161.sysnet.ucsd.edu [22.214.171.124], pleased to meet you
Don't worry about the fact that it says you're connecting from a
different machine (usher161)--that's an artifact of the NAT used on
our class cluster. Just make sure the machine name you provide
properly resolves (i.e., has a DNS entry), otherwise finicky
mailservers (like the one in the CS department!) will complain. We
can now ask it to deliver a message for us:
and it responds:
250 2.1.0 <email@example.com>... Sender ok
Now, we'll try sending ourselves a message:
You should obviously replace firstname.lastname@example.org with your own
250 2.1.5 ... Recipient ok
Note that many mailers enforce policy about who they will allow you to
send messages to. For example, you cannot send mail to a non-CS
account using the CS deparment mailers. For the UCSD mailer, if you
use an account not at UCSD, and you're connecting from a machine
outside of UCSD, you'll get a message like:
550 5.7.1 ... Relaying denied
Seems UCSD doesn't want to be bothered with handling other people's
mail. (Note that if you try to circumvent this by lying about your
hostname in the HELO message, the server may detect that and return a
450 error message here.) By now you're probably starting to
understand why sendmail is so complicated. Luckily we're going to
ignore all of these details in our MTA. Now, send your message:
This is a sample message.
Note that you must end your message with a . on a line by itself. The
server responds with:
250 2.0.0 h33J23M4002993 Message accepted for delivery
Great. Now we can log off.
221 2.0.0 smtp.ucsd.edu closing connection
Connection closed by foreign host.
If everything went well, you've now got mail! That's all there is to
it. Of course, what happened behind the scenes is that smtp.ucsd.edu
connected to the MTA at your mail server and repeated this whole
process in an automated fashion. That server then moved the mail to
your local mail spool. We're not going to worry about how that last
Building your MTA
The first thing you should do, if you're not already comfortable with
sockets programming, is check out MIT's excellent Using TCP through Sockets tutorial.
We have provided an initial skeleton directory to get you started. It
is available as /net/cluster/cse223b/sp10/labs/lab1.tgz on the
course cluster machines. You should copy this file to your working
directory. The following sequence of commands should extract the
files and build the initial (useless) executable:
% tar xzf lab1.tgz
% cd lab1
The tarball contains four files: domain.c, domain.h, Makefile, and
mta.C. You'll find the first two files useful for looking up the
destination MTA for messages you're trying to deliver (see the following
section on mail exchangers). The Makefile,
as the name implies, is a GNU makefile that builds the executable. (If
you are trying to build on FreeBSD, you should follow the directions in
the comments about how to edit the Makefile.)
You shouldn't need to know anything about make to use it, but if
you're curious, the documentation is
on-line. The last file, mta.C, is the one you're going to use to
write your MTA. Currently, it just accepts TCP connections, closes
them, and waits for another. You can run the executable by typing:
% ./mta 2225
Where 2225 is the port you want it to listen on. In order not to
conflict with the already running MTA (sendmail), you should run your
MTA on a port other than 25 (larger than 1024). During testing you're
likely to want to use something other than 2225 as well so it doesn't
conflict with other students working on their projects.
When determining where to send messages to, it would be nice if you
could just contact the destination directly. Unfortunately, many
domains have mail exchangers that receive mail. This is especially
important for you to know, as cs.ucsd.edu, the domain many of you use
for your email accounts, is NOT usually handled by a machine called
cs.ucsd.edu. Instead, there are six machines set up to handle mail for
the cs.ucsd.edu domain. These are stored in so-called MX records in
You can see for yourself using the dig command:
% dig mx cs.ucsd.edu
; <<>> DiG 9.3.4-P1 <<>> mx cs.ucsd.edu
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24388
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 4, ADDITIONAL: 9
;; QUESTION SECTION:
;cs.ucsd.edu. IN MX
;; ANSWER SECTION:
cs.ucsd.edu. 4623 IN MX 60 csemailhub.ucsd.edu.
cs.ucsd.edu. 4623 IN MX 70 inbound.ucsd.edu.
cs.ucsd.edu. 4623 IN MX 50 cse-inbound.ucsd.edu.
As you can see, csemailhub, inbound, and cse-inbound are the machines that
you should actually contact to send mail to a user at cs.ucsd.edu.
Which one you choose is up to you, but it may be the case that one or
more of them (csemailhub, for example) isn't functioning when you try to
send the message. In that case, you should try each entry in the list
Because MX processing is complicated business, we've provided some
code for you, in domain.c, that will handle the difficult parts.
getmxrr() will return an ordered list of machines that you can try to
deliver mail to for a given domain. mta.C includes some sample code
showing you how to use it.
Testing your MTA
The easiest way to test and debug your MTA is to use it interactively
just as we did above. Of course, once your MTA accepts messages,
you'll need to send them on. I'd suggest trying to send messages to
yourself so you can see if it actually succeeds! You might find
programs like Ethereal and Netcat (nc) useful to follow the communication between
your MTA and others.
Once you think your MTA is working, you can hook it up to a real
MUA and give it a whirl. The simplest way is to use your normal mail
reader (Eudora, Netscape, Mozilla, Outlook Express, etc.) and just
configure it to use your MTA rather than your default one.
For Mozilla, you can do this by going to Edit->Mail and Newsgroup
Account Settings and selecting the Outgoing Server (SMTP) tab. Enter
the name of the machine your MTA is running on (e.g.,
7.cse223b.snoeren.usher.ucsdsys.net) and port 2225. Make sure you turn off SSL (Never) and uncheck the
user name and password option.
Similar changes can be made to other mailers. I'll post them here if
anyone wants to email me how to do this in your own mail reader.
All code for this assignment must be written individually. You
are not allowed to look at anyone else's solutions or solutions to
similar assignments you may find for courses at UCSD or other
institutions. You may discuss the assignment with fellow students,
but all code you submit must be either yours alone or code that was
provided to you as part of the assignment.
The Makefile distributed in the lab tarball has the ability to tar up all of the
files in your directory. One consequence of this is that you should
make sure that all the files I need to compile your code are in this
directory. You might take this opportunity to include a README file
or somesuch giving me any instructions I might need about how to run
your code, known bugs, etc., etc. Do not modify the Makefile to
link in code outside of the working directory. When you're ready
to submit your code, you can execute the following command:
% gmake turnin
which will create a file called user-turnin.tgz, where user is your user ID, and
copy it to the submission directory. You might verify your tarball contains all the right things in the following fashion.
% mkdir tmp
% cd tmp
% tar xzf ../user-turnin.tgz
If all goes well, you've submitted your assignment. You are free to
resubmit at any time up to the deadline using the same mechanism. Only
your most recent submission is saved.