summaryrefslogtreecommitdiffstats
path: root/scratch/bash-3.1/examples/scripts.noah/send_mail.bash
blob: 24a12203757e6d52ba2207db4183003635ff198e (plain)
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
# send_mail.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-07-02
# Public domain

# Commentary:

# TODO: implement Fcc headers (see emacs manual)

# Code:

#:docstring send_mail:
# Usage: send_mail
#
# This function serves as a simple replacement for sendmail as a client
# interface on those systems where it is not available.  It does assume
# that one can talk to an SMTP mailer on port 25 either on the local host
# or on the host specified by the MAILHOST environment variable.  If you
# have access to sendmail, it's better to use 'sendmail -t' instead of this
# script (which probably isn't as robust).
#
# Message is read from stdin, and headers are parsed to determine
# recipients.  
#:end docstring:

###;;;autoload
function send_mail ()
{
    # Need gawk, since several extensions are taken advantage of (like
    # IGNORECASE for regexps).
    local awk="${GAWK_LOCATION:-gawk}"
    local DefaultFrom="${USER:-${LOGNAME}}"
    local From
    local To
    local Cc
    local Bcc
    local tmpfile="/tmp/send_mail$$"

    while [ -e "${tmpfile}" ]; do
       tmpfile="/tmp/send_mail${RANDOM}"
    done

    # Lines consisting only of dots need one more dot appended.  SMTP
    # servers eat one of the dots (and if only 1 dot appears, it signifies
    # the end of the message).
    sed '/^\.\.*/s/^\(\.\.*\)$/\1./' > "${tmpfile}"

    # Parse mail headers in message to extract recipients list. 
    # This doesn't affect what the user sees---it's only used to generate
    # the rcpt-to lines for SMTP. 
    eval $(${awk} -f - "${tmpfile}" <<- '__EOF__'
       # Try to extract email address from amidst random data
       function parse_address (data)
       {
           # From: "real name" <foobar@host>
           # From: "" <foobar@host>
           if (match(data, /^\"[^\"]*\"[ \t]*<.*>/)) {
              data_idx = match(data, /^\"[^\"]*\"[ \t]*</)
              data = substr(data, RSTART + RLENGTH);
              if (data_idx = match(data, ">.*"))
                 data = substr(data, 1, RSTART - 1);
              return data
           }
           # From: real name <foobar@host>
           if (match(data, /<.*>/)) {
              data_idx = match(data, /</)
              data = substr(data, RSTART + RLENGTH);
              if (data_idx = match(data, ">"))
                 data = substr(data, 1, RSTART - 1);
              return data
           }
           # From: foobar@host (real name)
           if (match(data, /\(.*\)/)) {
              data_idx = match(data, /\(/);
              data = substr(data, 1, RSTART - 1);
              return data
           }
           # (hopefully) From: foobar@host
           return data
       }

       BEGIN { IGNORECASE = 1; }

       # Blank line signifies end of headers, so we can stop looking.
       /^$/ { exit(0) }

       /^from:|^to:|^cc:|^bcc:/ {
          header_idx = match($0, /^[^:]*:/)
          if (header_idx) {
             # Capitalize header name
             header_firstchar = toupper(substr($0, RSTART, 1));
             header_rest = tolower(substr($0, RSTART + 1, RLENGTH - 2));
             header = header_firstchar header_rest

             $0 = substr($0, RSTART + RLENGTH + 1);
             addresses = ""
             # parse addresses
             while ($0) {
                # Strip leading whitespace
                if (idx = match($0, /[ \t]*/))
                   $0 = substr($0, RSTART + RLENGTH);

                # Find everything up to a nonquoted comma
                # FIXME: doesnt handle quoting yet
                if (idx = match($0, /,/)) {
                   data = substr($0, 1, RSTART);
                   $0 = substr($0, RSTART + 1);
                } else {
                   data = $0
                   $0 = ""
                }
                addresses = addresses " " parse_address(data)
             }

             printf("%s='%s'\n", header, addresses);
          }
       }
	__EOF__)

    # Not sure if an address is *required* after the HELO.. every sendmail
    # I tried talking to didn't seem to care.  Some sendmails don't care
    # if there's a HELO at all. 
    cat <<- __EOF__ | telnet ${MAILHOST:-localhost} 25 > /dev/null 2>&1
	HELO
	mail from: ${From:-${DefaultFrom}}
	$(for name in ${To} ${Cc} ${Bcc} ; do
	     echo "rcpt to: ${name}"
	  done)
	data
	$(cat "${tmpfile}")
	.
	quit
	__EOF__

    rm -f "${tmpfile}"
}

provide send_mail

# send_mail.bash ends here