/*********************************************************************
@version 1.2
@author James Driscoll maus@io.com
@author Alex Chaffee
Usage -
Version History:
0.8 5/15/96 - First version
0.9 5/16/96 - fixed date code, added localhost to HELO,
fixed Subject bug
0.91 7/10/96 - Yet another date fix, for European TimeZones. Man, they
gotta fix that code...
1.00 7/17/96 - renamed to Qsmtp, as I have plans for the SMTP code,
and I want to get this out and announced. Also cleaned it
up and commented out the DEBUG code (for size, just in case
the compiler didn't optimize it out on your machine - mine
didn't (Symantec Cafe Lite, you get what you pay for, and
I paid for a book)).
1.01 9/18/96 - Fixed the call to getLocalHost local, which 1.02 JDK didn't
like (Cafe Lite didn't mind, though). Think I'll be using
JDK for all compliations from now on. Also, added a close
method, since finalize() is not guarenteed to be called(!).
1.1 12/26/96 - Fixed problem with EOL, I was using the Unix EOL, not the
network end of line. A fragile mail server was barfing.
I can't beleive I wrote this - that's what half a year will do.
Also, yanked out the debug code. It annoyed me.
1.11 12/27/97 - Forgot to flush(), println used to do that for me...
1.2 9/19/98 adc
- Added headers
- Multiple recipients possible
- message can contain headers
***********************************************************************/
package com.purpletech.net;
import java.net.*;
import java.io.*;
import java.util.*;
/**
* SMTP client. Based on code by James Driscoll maus@io.com.
*
*
Qsmtp Class
*
* by Alex Chaffee,
* Purple Technology
*
*
* This class provides a quick and dirty way to send email from any Java
* program (including servlets and applets). It is based on the Qsmtp
* class by Jim Driscoll, but I've added the ability to add multiple
* recipients and extra headers.
*
*
*
* Note: You may want to remove the package statement so it will compile
* correctly inside the root directory of your project.
*
*
* Files
*
* Download the source code.
*
*
*
*
See also:
*
*
*
* @author James Driscoll maus@io.com
* @author Alex alex@purpletech.com
**/
public class Qsmtp
{
static final int DEFAULT_PORT = 25;
// static final String EOL = "\n";
static final String EOL = "\r\n"; // network end of line
protected String host;
protected DataInputStream reply = null;
protected PrintStream send = null;
protected Socket sock = null;
protected Dictionary headers = new Hashtable();
/**
* Create a Qsmtp object pointing to the specified host
* @param hostid The host to connect to.
* @exception UnknownHostException
* @exception IOException
*/
public Qsmtp(String hostid) throws UnknownHostException, IOException
{
this(hostid, DEFAULT_PORT);
}
public Qsmtp(String hostid, int port) throws UnknownHostException, IOException
{
host = hostid;
sock = new Socket(hostid, port);
reply = new DataInputStream(sock.getInputStream());
send = new PrintStream(sock.getOutputStream());
String rstr = reply.readLine();
if (!rstr.startsWith("220")) throw new ProtocolException(rstr);
while (rstr.indexOf('-') == 3)
{
rstr = reply.readLine();
if (!rstr.startsWith("220")) throw new ProtocolException(rstr);
}
initHeaders();
}
public Qsmtp(InetAddress address) throws IOException
{
this(address, DEFAULT_PORT);
}
public Qsmtp(InetAddress address, int port) throws IOException
{
host = address.getHostAddress();
sock = new Socket(address, port);
reply = new DataInputStream(sock.getInputStream());
send = new PrintStream(sock.getOutputStream());
String rstr = reply.readLine();
if (!rstr.startsWith("220")) throw new ProtocolException(rstr);
while (rstr.indexOf('-') == 3)
{
rstr = reply.readLine();
if (!rstr.startsWith("220")) throw new ProtocolException(rstr);
}
}
public String getHost()
{
return host;
}
public void initHeaders()
{
// Warn the world that we are on the loose - with the comments header:
headers.put("Comment", "Unauthenticated sender");
headers.put("X-Mailer", "Java Qsmtp");
}
public void setHeader(String name, String value)
{
headers.put(name, value);
}
public void addTo(String address)
{
String to;
to = (String) headers.get("To");
if (to == null)
to = address;
else
to = to + ", " + address;
headers.put("To", to);
}
public void sendmsg(String from, String to,
String subject, String message)
throws IOException, ProtocolException
{
setHeader("From", from);
setHeader("To", to);
setHeader("Subject", subject);
sendmsg(message);
}
public void sendmsg(String message)
throws IOException, ProtocolException
{
String rstr;
String sstr;
// Create Date - we'll cheat by assuming that local clock is right
headers.put("Date", msgDateFormat(new Date()));
// If the message starts with header lines, parse them
message = addHeaders(message);
InetAddress local;
String host;
try
{
local = InetAddress.getLocalHost();
host = local.getHostName();
}
catch (UnknownHostException ioe)
{
System.err.println("No local IP address found - is your network up?");
host = "localhost";
}
sendLine("HELO " + host, "250");
sendLine("MAIL FROM: <" + headers.get("From") + ">", "250");
String to = (String) headers.get("To");
if (to == null || to.equals(""))
throw new ProtocolException("No recipients! You must specify a 'To' header.");
StringTokenizer tok = new StringTokenizer(to, ",");
while (tok.hasMoreTokens())
{
String next = (String) tok.nextToken();
sendLine("RCPT TO: <" + next + ">", "250");
}
sendLine("DATA", "354");
// print the headers
printHeaders();
// Sending a blank line ends the header part.
send.print(EOL);
// Now send the message proper
send.print(message);
if (!message.endsWith("\n"))
send.print(EOL);
sendLine(".", "250");
}
private void printHeaders()
{
Enumeration e = headers.keys();
while (e.hasMoreElements())
{
String header = (String) e.nextElement();
String value = (String) headers.get(header);
send.print(header);
send.print(": ");
send.print(value);
send.print(EOL);
}
}
void sendLine(String line, String success)
throws IOException, ProtocolException
{
send.print(line);
send.print(EOL);
send.flush();
String rstr = reply.readLine();
if (!rstr.startsWith(success)) throw new ProtocolException(rstr);
}
String addHeaders(String message)
{
try
{
BufferedReader in = new BufferedReader
(new StringReader(message));
String line = in.readLine();
int colon = line.indexOf(':');
if ((colon != -1) &&
(line.charAt(colon + 1) == ' ') &&
(line.substring(0, colon).indexOf(' ') == -1))
{
// we're in header land
while (!line.equals(""))
{
colon = line.indexOf(':');
if (colon == -1)
break;
String header = line.substring(0, colon);
String value = line.substring(colon + 2);
headers.put(header, value);
line = in.readLine();
}
StringWriter s = new StringWriter();
PrintWriter out = new PrintWriter(s);
while ((line = in.readLine()) != null)
out.println(line);
return s.toString();
}
}
catch (IOException e)
{
e.printStackTrace();
}
return message;
}
public void close()
{
try
{
send.print("QUIT");
send.print(EOL);
send.flush();
sock.close();
}
catch (IOException ioe)
{
// As though there's anything I can do about it now...
}
}
protected void finalize() throws Throwable
{
this.close();
super.finalize();
}
private String msgDateFormat(Date senddate)
{
String formatted = "hold";
String Day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
String Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
formatted = Day[senddate.getDay()] + ", ";
formatted = formatted + String.valueOf(senddate.getDate()) + " ";
formatted = formatted + Month[senddate.getMonth()] + " ";
if (senddate.getYear() > 99)
formatted = formatted + String.valueOf(senddate.getYear() + 1900) + " ";
else
formatted = formatted + String.valueOf(senddate.getYear()) + " ";
if (senddate.getHours() < 10) formatted = formatted + "0";
formatted = formatted + String.valueOf(senddate.getHours()) + ":";
if (senddate.getMinutes() < 10) formatted = formatted + "0";
formatted = formatted + String.valueOf(senddate.getMinutes()) + ":";
if (senddate.getSeconds() < 10) formatted = formatted + "0";
formatted = formatted + String.valueOf(senddate.getSeconds()) + " ";
if (senddate.getTimezoneOffset() < 0)
formatted = formatted + "+";
else
formatted = formatted + "-";
if (Math.abs(senddate.getTimezoneOffset()) / 60 < 10) formatted = formatted + "0";
formatted = formatted + String.valueOf(Math.abs(senddate.getTimezoneOffset()) / 60);
if (Math.abs(senddate.getTimezoneOffset()) % 60 < 10) formatted = formatted + "0";
formatted = formatted + String.valueOf(Math.abs(senddate.getTimezoneOffset()) % 60);
return formatted;
}
}