_ns_sendmail
one of the defined (but not documented) Tcl procedures in this
installation of the ACS
Usage:
_ns_sendmail smtp smtpport timeout tolist bcclist from subject body extraheaders
Source code:
## Put the tolist in the headers
set rfcto [join $tolist ", "]
## Build headers
set msg "To: $rfcto\nFrom: $from\nSubject: $subject\nDate: [ns_httptime [ns_time]]"
## Insert extra headers, if any (not for BCC)
set message_id_already_done_p 0
if {$extraheaders ne ""} {
set size [ns_set size $extraheaders]
for {set i 0} {$i < $size} {incr i} {
set key [ns_set key $extraheaders $i]
if { [string equal $key {Message-ID}] } {
set message_id_already_done_p 1
}
append msg "\n${key}: [ns_set value $extraheaders $i]"
}
}
# Insert a unique "Message-ID:" header, but only if the caller did
# not manually include a Message-ID header:
#
# An application could use the Message-ID header for
# e.g. threading support, but we're not trying to do anything
# fancy like that here. We just want to include a globally-unique
# ID. Why? Well, for one thing, since most email user agents
# include a Message-ID, but most SPAM software does not, some
# anti-SPAM software filters out email which does not have a
# Message-ID...
#
# Note: The $message_id below is guaranteed to be globally unique
# if and only if *ALL* of the following conditions are true:
#
# 1. Your unix box's hostname (which is what [ns_info hostname]
# returns) is set to a fully-qualified name like
# "philip.greenspun.com", NOT just a local hostname like
# "philip".
# 2. Your fully-qualified hostname is in fact globally-unique.
# AKA, you didn't do something foolish like set up two separate
# machines that both think their hostname is
# "philip.greenspun.com".
# 3. On your unix host, you have only ONE AOLserver running with
# the server name returned by [ns_info server].
# 4. Since [ns_info boottime] is in seconds, you never restart
# your AOLserver multiple times in < 1 second, jump your system
# clock backwards in time, or etc.
# 5. Once the "ns_sendmail sequence" nsv variable is set, you
# never manually fool with it to re-set it to a previous value.
# While the server is running, this value must always increase,
# never decrease.
#
# --atp@piskorski.com, 2001/10/11 11:51 EDT
# For more info on messgage-id and other email fields, see RFC 2822:
# http://www.faqs.org/rfcs/rfc2822.html
if { ! $message_id_already_done_p } {
set message_id "[nsv_incr ns_sendmail sequence].[ns_info boottime].[ns_info server]@[ns_info hostname]"
append msg "\nMessage-ID: <$message_id>"
}
## Blank line between headers and body
append msg "\n\n$body\n"
## Terminate body with a solitary period
foreach line [split $msg "\n"] {
if {"." eq $line} {
append data .
}
append data $line
append data "\r\n"
}
append data .
## Open the connection
set sock [ns_sockopen $smtp $smtpport]
set rfp [lindex $sock 0]
set wfp [lindex $sock 1]
## Strip "from:" email address
regexp {.*<(.*)>} $from ig from
## Perform the SMTP conversation
if { [catch {
_ns_smtp_recv $rfp 220 $timeout
_ns_smtp_send $wfp "HELO [ns_info hostname]" $timeout
_ns_smtp_recv $rfp 250 $timeout
_ns_smtp_send $wfp "MAIL FROM:<$from>" $timeout
_ns_smtp_recv $rfp 250 $timeout
# TODO: Above, should optionally take a "Return-Path" to use
# as the envelope sender address (aka, envelope return path)
# rather than always using $from. This would allow using
# VERPs, for instance, as discussed at:
# "http://cr.yp.to/proto/verp.txt"
# See also discussion at:
# "http://www.arsdigita.com/bboard/q-and-a-fetch-msg?msg%5fid=000awU"
# --atp@piskorski.com, 2001/10/11 10:25 EDT
## Loop through To and BCC list via multiple RCPT TO lines
## A BCC should never, ever appear in the header
foreach toto [concat $tolist $bcclist] {
#transform "Fritz <fritz@foo.com>" into "fritz@foo.com"
regexp {.*<(.*)>} $toto ig toto
_ns_smtp_send $wfp "RCPT TO:<$toto>" $timeout
_ns_smtp_recv $rfp 250 $timeout
}
_ns_smtp_send $wfp DATA $timeout
_ns_smtp_recv $rfp 354 $timeout
_ns_smtp_send $wfp $data $timeout
_ns_smtp_recv $rfp 250 $timeout
_ns_smtp_send $wfp QUIT $timeout
_ns_smtp_recv $rfp 221 $timeout
} errMsg ] } {
## Error, close and report
close $rfp
close $wfp
return -code error $errMsg
}
## Close the connection
close $rfp
close $wfp
philg@mit.edu