Solution for the Mail Client Lab

The following code presents one solution for the mail client lab. It includes only the SMTPConnection.java class, since the other classes do not need to be modified in the basic lab.

SMTPConnection.java

  1. import java.net.*;
  2. import java.io.*;
  3. import java.util.*;
  4.  
  5. /* $Id: SMTPConnection.java,v 1.1.1.1 2003/09/30 14:36:01 kangasha Exp $ */
  6.  
  7. /**
  8. * Open an SMTP connection to a remote machine and send one mail.
  9. *
  10. * @author Jussi Kangasharju
  11. */
  12. public class SMTPConnection {
  13. /* The socket to the server */
  14. public Socket connection;
  15.  
  16. /* Streams for reading and writing the socket */
  17. public BufferedReader fromServer;
  18. public DataOutputStream toServer;
  19.  
  20. /* Just to make it look nicer */
  21. private static final int SMTP_PORT = 25;
  22. private static final String CRLF = "\r\n";
  23.  
  24. /* Are we connected? Used in close() to determine what to do. */
  25. private boolean isConnected = false;
  26.  
  27. /* Create an SMTPConnection object. Create the socket and the
  28. associated streams. Send HELO-command and check for errors. */
  29. public SMTPConnection(Envelope envelope) throws IOException {
  30. connection = new Socket(envelope.DestAddr, SMTP_PORT);
  31. fromServer = new
  32. BufferedReader(new InputStreamReader(connection.getInputStream()));
  33. toServer = new DataOutputStream(connection.getOutputStream());
  34.  
  35. String reply = fromServer.readLine();
  36. if(parseReply(reply) != 220) {
  37. System.out.println("Error in connect.");
  38. System.out.println(reply);
  39. return;
  40. }
  41. String localhost = (InetAddress.getLocalHost()).getHostName();
  42. try {
  43. sendCommand("HELO " + localhost, 250);
  44. } catch (IOException e) {
  45. System.out.println("HELO failed. Aborting.");
  46. return;
  47. }
  48. isConnected = true;
  49. }
  50.  
  51. /* Send the message. Simply writes the correct SMTP-commands in the
  52. correct order. No checking for errors, just throw them to
  53. the caller. */
  54. public void send(Envelope envelope) throws IOException {
  55. sendCommand("MAIL FROM:<" + envelope.Sender + ">", 250);
  56. sendCommand("RCPT TO:<" + envelope.Recipient + ">", 250);
  57. sendCommand("DATA", 354);
  58. sendCommand(envelope.Message.toString() + CRLF + ".", 250);
  59. }
  60.  
  61. /* Close the connection. Try to send QUIT-commmand and then close
  62. the socket. */
  63. public void close() {
  64. isConnected = false;
  65. try {
  66. sendCommand("QUIT", 221);
  67. connection.close();
  68. } catch (IOException e) {
  69. System.out.println("Unable to close connection: " + e);
  70. isConnected = true;
  71. }
  72. }
  73.  
  74. /* Send an SMTP command to the server. Check for reply code. Does
  75. not check for multiple reply codes (required for RCPT TO). */
  76. private void sendCommand(String command, int rc) throws IOException {
  77. String reply = null;
  78.  
  79. toServer.writeBytes(command + CRLF);
  80. reply = fromServer.readLine();
  81. if(parseReply(reply) != rc) {
  82. System.out.println("Error in command: " + command);
  83. System.out.println(reply);
  84. throw new IOException();
  85. }
  86.  
  87. }
  88.  
  89. /* Parse the reply line from the server. Returns the reply code. */
  90. private int parseReply(String reply) {
  91. StringTokenizer parser = new StringTokenizer(reply);
  92. String replycode = parser.nextToken();
  93. return (new Integer(replycode)).intValue();
  94. }
  95.  
  96. /* Destructor. Closes the connection if something bad happens. */
  97. protected void finalize() throws Throwable {
  98. if(isConnected) {
  99. close();
  100. }
  101. super.finalize();
  102. }
  103. }