Documentation can be found at http://tcllib.sourceforge.net/doc/smtpd.html
Note: The tcllib smtpd package is a framework for writing Mail Transfer Agents (MTA). It does not handle delivery but provides hooks to program against. Its function is to provide a correct interface to SMTP network clients; "correct" here means, in conformance with RFCs 821 and 2821 [L1 ].
Here's a simple example (found in the tcllib examples tree):
#! /bin/sh # # tk_smtpd - Copyright (C) 2001 Pat Thoyts <[email protected]> # # Simple test of the mail server. All incoming messages are displayed in a # message dialog. # # This example works nicely under Windows or within tkcon. # # Usage tk_smtpd 0.0.0.0 8025 # or tk_smtpd 127.0.0.1 2525 # or tk_smtpd # to listen to the default port 25 on all tcp/ip interfaces. # # ------------------------------------------------------------------------- # This software is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the file 'license.terms' for # more details. # ------------------------------------------------------------------------- # \ exec wish8.3 "$0" ${1+"$@"} package require smtpd package require Tk wm withdraw . # Handle new mail by raising a message dialog for each recipient. proc deliver {sender recipients data} { if {[catch {eval array set saddr [mime::parseaddress $sender]}]} { error "invalid sender address \"$sender\"" } set mail "From $saddr(address) [clock format [clock seconds]]" append mail "\n" [join $data "\n"] foreach rcpt $recipients { if {! [catch {eval array set addr [mime::parseaddress $rcpt]}]} { tk_messageBox -title "To: $addr(address)" -message $mail } } } # Accept everyone except those spammers on 192.168.1.* :) proc validate_host {ipnum} { if {[string match "192.168.1.*" $ipnum]} { error "your domain is not allowed to post, Spammers!" } } # Accept mail from anyone except user 'denied' proc validate_sender {address} { eval array set addr [mime::parseaddress $address] if {[string match "denied" $addr(local)]} { error "mailbox $addr(local) denied" } return } # Only reject mail for recipients beginning with 'bogus' proc validate_recipient {address} { eval array set addr [mime::parseaddress $address] if {[string match "bogus*" $addr(local)]} { error "mailbox $addr(local) denied" } return } # Setup the mail server smtpd::configure \ -deliver ::deliver \ -validate_host ::validate_host \ -validate_recipient ::validate_recipient \ -validate_sender ::validate_sender # Run the server on the default port 25. For unix change to # a high numbered port eg: 2525 or 8025 etc with # smtpd::start 127.0.0.1 8025 or smtpd::start 0.0.0.0 2525 set iface 0.0.0.0 set port 25 if {$argc > 0} { set iface [lindex $argv 0] } if {$argc > 1} { set port [lindex $argv 1] } smtpd::start $iface $port # # Local variables: # mode: tcl # indent-tabs-mode: nil # End:
The following will take and only send the message to unique destinations. It uses both the smtpd and smtp packages.
##
## Program to ensure that duplicate messages are not sent from ClearQuest
## to a given recipient
##
##
## Require any packages that will be used
##
package require Tcl
package require mime
package require smtpd
package require smtp
package require log
package require msgcat
##
## Set global variables
##
set allowedUserPatternList {*}
set allowedHostIPList {127.0.0.1}
set mailForwardingHost {houmailgwi1.hou.aspentech.com}
set mailForwardingPort 25
##
## Uncomment the following lines after the "##+" up to the "##-" to turn
## off messages, comment them out to turn messages on
##
##+
#::log::lvSuppress debug
#::log::lvSuppress notice
##-
##
## validateHost - Checks to see if a host is legal
##
## Arguments:
## ipnum - IP address of sender
##
proc validateHost {ipnum} {
global allowedHostIPList
##
## Loop through the patterns and check for a match
##
foreach allowedIP $allowedHostIPList {
if {[string equal $allowedIP $ipnum]} then {
::log::log debug [::msgcat::mc ip.granted $ipnum]
return;
}
}
##
## No matches, so we throw an error to deny access
##
::log::log debug [::msgcat::mc ip.denied $ipnum]
return -code error deny
return
}
##
## validateSender - Checks to see if a sender if legeal
##
## Arguments:
## address - sender's e-mail address
##
proc validateSender {address} {
global allowedUserPatternList
##
## Loop through the patterns and check for a match
##
foreach allowedPattern $allowedUserPatternList {
if {[string match $allowedPattern $address]} then {
::log::log debug [::msgcat::mc sender.granted $address]
return;
}
}
##
## No matches, so we throw an error to deny access
##
::log::log debug [::msgcat::mc sender.denied $address]
return -code error deny
}
##
## processMail - Procedure that processes a mail message
##
## Arguments:
## args - accept any arguments
##
proc processMail {sender recipients data} {
global mailForwardingHost
global mailForwardingPort
global LastData
##
## Send the mail
##
::log::log debug [::msgcat::mc process.sending $data]
set LastData $data
set token [mime::initialize -string [join $data "\n"]]
set results [smtp::sendmessage $token \
-servers $mailForwardingHost \
-ports $mailForwardingPort \
-queue 0 \
-atleastone 1 \
-originator $sender \
-recipients [lsort -unique $recipients] \
]
mime::finalize $token -subordinates all
if {[llength $results]} then {
::log::log debug [::msgcat::mc process.failure $results]
}
##
## Return to caller
##
return
}
##
## ok - Procedure that always returns a successful validation
##
## Arguments:
## args - accept any arguments
##
proc ok {args} {
return
}
##
## Main code body
##
##
## Initialize Message Catalog
##
set msgDir [file join [file dirname [info script]] msgs]
::msgcat::mcload $msgDir
##
## Setup to receive mail
##
::smtpd::configure \
-validate_host validateHost \
-validate_sender validateSender \
-validate_recipient ok \
-deliver processMail
##
## Kick off the whole thing
##
::log::log debug [::msgcat::mc starting]
::smtpd::start
----
Here is the associated message file:
##
## Message file ClearQuest Smtp Deamon
##
::msgcat::mcset c ip.granted {Access granted to host "%s"}
::msgcat::mcset c ip.denied {Access denied to host "%s"}
::msgcat::mcset c sender.granted {Access granted to sender "%s"}
::msgcat::mcset c sender.denied {Access denied to sender "%s"}
::msgcat::mcset c process.original {Orginal recipients "%s"}
::msgcat::mcset c process.resultant {Resultant recipients "%s"}
::msgcat::mcset c process.sending {Sending "%s"}
::msgcat::mcset c process.failure {Message failed to be sent to {%s}}
::msgcat::mcset c starting {ClearQuest SMTP Deamon Started}Fakemail [L2 ] is a maintained project for a small dummy SMTP daemon for testing.
Hmm - fakemail is stinky perl - the tcllib smtpd package is also maintained and is beautiful tcl :) 'Anyone motivated enough to determine whether there's any functionality smtpd can learn from fakemail?