1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/** -*-C-*-ish
Kaya standard library
Copyright (C) 2004, 2005 Edwin Brady
This file is distributed under the terms of the GNU Lesser General
Public Licence. See COPYING for licence.
*/
module Mail;
// Module for talking to an SMTP server
// Maybe add IMAP/POP3 support later?
import Prelude;
import Net;
import Strings;
import Regex;
import Time;
"SMTP Connection handle."
data SMTPConnection = SMTP(NetHandle h, String host);
Exception CantConnect = Exception("Can't Connect",150);
Exception SMTPError(String err) = Exception("SMTP Error:" + err,151);
Exception HeaderError(String err) = Exception("Invalid Header: " + err,152);
"Send a mail.
Sends from address <em>from</em>, to <em>whoto</em>.
Additional headers may be stored in <em>headers</em>.
Message contents <em>body</em> may not contain headers."
public Void sendmail(String from, String whoto, [(String,String)] headers,
String body, String server="localhost", Int port=25)
{
// check data and construct message
blacklist = compile("[\r\n]",[IgnoreCase,Multiline]);
if (quickMatchWith(blacklist,from)) {
throw(HeaderError("From is "+from));
}
if (quickMatchWith(blacklist,whoto)) {
throw(HeaderError("To is "+whoto));
}
msg = "";
for header in headers {
if (quickMatchWith(blacklist,header.fst) || quickMatchWith(blacklist,header.snd)) {
throw(HeaderError(header.fst+" is "+header.snd));
}
msg += header.fst+": "+header.snd+"\n";
}
msg += "From: "+from+"\n";
msg += "To: "+whoto+"\n";
msg += "Date: "+rfc2822Time(gmtime())+"\n\n"; // end headers
msg += body;
c = smtpConnect(server,port);
smtpFrom(c,from);
smtpRcpt(c,whoto);
smtpData(c,msg);
smtpClose(c);
}
"Create an SMTP connection"
public SMTPConnection smtpConnect(String host, Int port=25)
{
h = connect(TCP,host,port);
rcvok = recv(h,255,30);
if ((words(rcvok)[0])!="220") {
throw(CantConnect);
}
send(h,"HELO "+host+"\n");
rcvok = recv(h,255,30);
if ((words(rcvok)[0])!="250") {
throw(CantConnect);
}
return SMTP(h,host);
}
Void smtpFrom(SMTPConnection c, String from)
{
send(c.h,"MAIL FROM:"+from+"\n");
rcvok = recv(c.h,255,30);
if ((words(rcvok)[0])!="250") {
throw(SMTPError(rcvok));
}
}
Void smtpRcpt(SMTPConnection c, String whoto)
{
addresses = split(",",whoto);
for address in addresses {
trim(address);
send(c.h,"RCPT TO:"+address+"\n");
rcvok = recv(c.h,255,30);
if ((words(rcvok)[0])!="250") {
throw(SMTPError(rcvok));
}
}
}
Void manglePeriod(var String stuff)
{
slines = lines(stuff);
newstuff = "";
for x in slines {
if (length(x) > 0 && head(x)=='.') {
x = "."+x;
}
newstuff += x +"\n";
}
stuff = newstuff;
}
// Send data. Returns message id.
Void smtpData(SMTPConnection c, String stuff)
{
send(c.h,"DATA\n");
rcvok = recv(c.h,255,30);
if ((words(rcvok)[0])!="354") {
throw(SMTPError(rcvok));
}
// Mangle stuff in case any lines start with a .
manglePeriod(stuff);
send(c.h,stuff+"\n");
send(c.h,".\n");
rcvok = recv(c.h,255,30);
if ((words(rcvok)[0])!="250") {
throw(SMTPError(rcvok));
}
}
Void smtpClose(SMTPConnection c)
{
send(c.h,"QUIT\n");
rcvok = recv(c.h,255,30);
if ((words(rcvok)[0])!="221") {
throw(SMTPError(rcvok));
}
}
|