UCSD Main WebsiteUCSD Jacobs SchoolDepartment of Computer Science and Engineering
spacer gif
spacer gif
CSE 223B
spacer gifspacer gif
spacer gif
spacer gifCourse Overview
spacer gifspacer gifStructure
spacer gifspacer gifGrading
spacer gifspacer gifUseful books
spacer gif
spacer gifspacer gifSchedule
spacer gif
spacer gifspacer gifReadings
spacer gif
spacer gifLabs
spacer gif   Lab 1
spacer gif   Lab 2
spacer gif
spacer gif
spacer gif
Search
spacer gifspacer gifspacer gif
Advanced search  arrows gif

spacer gif
spacer gifspacer gif
spacer gif
spacer gif
spacer gif
spacer gif
spacer gifspacer gifspacer gif
spacer gif Lab 1: Charlie on the MTA
Due: 11:00am, Thursday, April 7th, 2011

Preliminaries

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.

Specification

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:

  • 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 fork() or thread creation system calls.
  • You do not need to handle messages with more than 255 recipients.
  • You do not need to handle mail messages larger than 65535 bytes.
  • 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.
You do not need to bother with the following things. You should just ignore them as best you can.
  • 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 user@domain.name, 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 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 line.
  • You should ignore all headers in the DATA portion of the message. Further, you do not need to implement any sort of loop detection.
If you are able to send a simple email message using your MTA, you're in good shape.

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:
Trying 132.239.1.49...
Connected to smtp.ucsd.edu.
Escape character is '^]'.
220 smtp.ucsd.edu ESMTP Sendmail 8.13.8/8.13.8; Mon, 28 Mar 2011 13:37:53 -0700
The first three lines are output from the telnet program. The last is the greeting sent by the MTA (Sendmail, surprise, surprise) at smtp.ucsd.edu. You can then identify yourself using the HELO command:
HELO sysnet30.ucsd.edu
and the MTA returns
250 smtp.ucsd.edu Hello sysnet30.ucsd.edu [137.110.222.40], pleased to meet you
Mmke 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:
MAIL FROM:<223bstudent@ucsd.edu>
and it responds:
250 2.1.0 <223bstudent@ucsd.edu>... Sender ok
Now, we'll try sending ourselves a message:
RCPT TO:<223baccount@ucsd.edu>
You should obviously replace 223baccount@ucsd.edu with your own account name.
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:
DATA
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.
QUIT
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 step happens.

Mail exchangers

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 the DNS.

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: 2, AUTHORITY: 4, ADDITIONAL: 7

;; QUESTION SECTION:
;cs.ucsd.edu.			IN	MX

;; ANSWER SECTION:
cs.ucsd.edu.		4623	IN	MX	10 oec-vmmx.ucsd.edu.
cs.ucsd.edu.		4623	IN	MX	5 inbound.ucsd.edu.

...
As you can see, oec-vmmx and 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 (inbound, for example) isn't functioning when you try to send the message. In that case, you should try each entry in the list in turn.

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.

Building your MTA (C/C++)

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 /cse223b/sp11/labs/lab1/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
% gmake
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.

Building your MTA (Java)

For those of you who choose to use Java, we have provided two files to get you started in /cse223b/sp11/labs/lab1: MTA.java and MXDomain.java. You may not import JavaMail, SMTPClient, or any other mail-related libraries in your code! If you are unsure about a library that you want to use, ask the TA!

MXDomain.java provides a simple method for obtaining DNS MX records, similar to what's provided in domain.c for the C/C++ skeleton code. It exports a single function called getMXRecords which, when given domain name string, returns a Java ArrayList of MXRecord objects from the DNSJava library. Be sure to include the DNSJava jar file (/usr/share/java/dnsjava.jar) in your classpath before using this class!

MTA.java contains the skeleton MTA code. Like the C version, it does nothing more than create a socket, accept TCP connections, closes them, and waits for another. You can build it by running:

% javac MTA.java
After a successful build, you can start the server by executing:
% java 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.

Building your MTA (Python)

We also provide a skeleton Python file, mta.py, in /cse223b/sp11/labs/lab1. Like the C and Java versions, it listens for incoming connections, accepts a client, closes the connection, and waits for another. If you choose to use Python, you may not import email, mimelib, smtplib, or any other mail-related modules into your code! If you are unsure about a module that you want to use, ask the TA!

Looking up MX records in Python is fairly straightforward:

import dns.resolver

dns_result = dns.resolver.query('cs.ucsd.edu', 'MX')

for mx_record in dns_result:
    print mx_record
Outputs:
10 oec-vmmx.ucsd.edu
5 inbound.ucsd.edu
You can also access individual elements of the dns_result collection via standard subscript notation: dns_result[0], dns_result[1], etc., and the number of elements is available via len().

You can run the code by executing:

python mta.py 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.

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., sysnet30.ucsd.edu) 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.

Collaboration policy

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.

Turnin procedure

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
% make
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.


spacer gif

spacer gif
spacer gifback to top ^
spacer gif
spacer gif
spacer gif
spacer gif
9500 Gilman Drive, La Jolla, CA 92093-0114
spacer gif
About CSE | CSE People | Faculty & Research | Graduate Education | Undergraduate Education
Department Administration | Contact CSE | Help | Search | Site map | Home
snoeren@cs.ucsd.edu
Official web page of the University of California, San Diego
Copyright © 2002 Regents of the University of California. All rights reserved.
spacer gif