Patch-ID: bash41-003
[bash.git] / examples / scripts.noah / send_mail.bash
blob24a12203757e6d52ba2207db4183003635ff198e
1 # send_mail.bash
2 # Author: Noah Friedman <friedman@prep.ai.mit.edu>
3 # Created: 1992-07-02
4 # Public domain
6 # Commentary:
8 # TODO: implement Fcc headers (see emacs manual)
10 # Code:
12 #:docstring send_mail:
13 # Usage: send_mail
15 # This function serves as a simple replacement for sendmail as a client
16 # interface on those systems where it is not available. It does assume
17 # that one can talk to an SMTP mailer on port 25 either on the local host
18 # or on the host specified by the MAILHOST environment variable. If you
19 # have access to sendmail, it's better to use 'sendmail -t' instead of this
20 # script (which probably isn't as robust).
22 # Message is read from stdin, and headers are parsed to determine
23 # recipients.
24 #:end docstring:
26 ###;;;autoload
27 function send_mail ()
29 # Need gawk, since several extensions are taken advantage of (like
30 # IGNORECASE for regexps).
31 local awk="${GAWK_LOCATION:-gawk}"
32 local DefaultFrom="${USER:-${LOGNAME}}"
33 local From
34 local To
35 local Cc
36 local Bcc
37 local tmpfile="/tmp/send_mail$$"
39 while [ -e "${tmpfile}" ]; do
40 tmpfile="/tmp/send_mail${RANDOM}"
41 done
43 # Lines consisting only of dots need one more dot appended. SMTP
44 # servers eat one of the dots (and if only 1 dot appears, it signifies
45 # the end of the message).
46 sed '/^\.\.*/s/^\(\.\.*\)$/\1./' > "${tmpfile}"
48 # Parse mail headers in message to extract recipients list.
49 # This doesn't affect what the user sees---it's only used to generate
50 # the rcpt-to lines for SMTP.
51 eval $(${awk} -f - "${tmpfile}" <<- '__EOF__'
52 # Try to extract email address from amidst random data
53 function parse_address (data)
55 # From: "real name" <foobar@host>
56 # From: "" <foobar@host>
57 if (match(data, /^\"[^\"]*\"[ \t]*<.*>/)) {
58 data_idx = match(data, /^\"[^\"]*\"[ \t]*</)
59 data = substr(data, RSTART + RLENGTH);
60 if (data_idx = match(data, ">.*"))
61 data = substr(data, 1, RSTART - 1);
62 return data
64 # From: real name <foobar@host>
65 if (match(data, /<.*>/)) {
66 data_idx = match(data, /</)
67 data = substr(data, RSTART + RLENGTH);
68 if (data_idx = match(data, ">"))
69 data = substr(data, 1, RSTART - 1);
70 return data
72 # From: foobar@host (real name)
73 if (match(data, /\(.*\)/)) {
74 data_idx = match(data, /\(/);
75 data = substr(data, 1, RSTART - 1);
76 return data
78 # (hopefully) From: foobar@host
79 return data
82 BEGIN { IGNORECASE = 1; }
84 # Blank line signifies end of headers, so we can stop looking.
85 /^$/ { exit(0) }
87 /^from:|^to:|^cc:|^bcc:/ {
88 header_idx = match($0, /^[^:]*:/)
89 if (header_idx) {
90 # Capitalize header name
91 header_firstchar = toupper(substr($0, RSTART, 1));
92 header_rest = tolower(substr($0, RSTART + 1, RLENGTH - 2));
93 header = header_firstchar header_rest
95 $0 = substr($0, RSTART + RLENGTH + 1);
96 addresses = ""
97 # parse addresses
98 while ($0) {
99 # Strip leading whitespace
100 if (idx = match($0, /[ \t]*/))
101 $0 = substr($0, RSTART + RLENGTH);
103 # Find everything up to a nonquoted comma
104 # FIXME: doesnt handle quoting yet
105 if (idx = match($0, /,/)) {
106 data = substr($0, 1, RSTART);
107 $0 = substr($0, RSTART + 1);
108 } else {
109 data = $0
110 $0 = ""
112 addresses = addresses " " parse_address(data)
115 printf("%s='%s'\n", header, addresses);
118 __EOF__)
120 # Not sure if an address is *required* after the HELO.. every sendmail
121 # I tried talking to didn't seem to care. Some sendmails don't care
122 # if there's a HELO at all.
123 cat <<- __EOF__ | telnet ${MAILHOST:-localhost} 25 > /dev/null 2>&1
124 HELO
125 mail from: ${From:-${DefaultFrom}}
126 $(for name in ${To} ${Cc} ${Bcc} ; do
127 echo "rcpt to: ${name}"
128 done)
129 data
130 $(cat "${tmpfile}")
132 quit
133 __EOF__
135 rm -f "${tmpfile}"
138 provide send_mail
140 # send_mail.bash ends here