2 Copyright (C) 2000-2003 Kern Sibbald and John Walker
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of
7 the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public
15 License along with this program; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 Derived from a SMTPclient:
24 SMTPclient -- simple SMTP client
26 Copyright (C) 1997 Ralf S. Engelschall, All Rights Reserved.
30 Kern Sibbald, July 2001
46 static char *from_addr = NULL;
47 static char *cc_addr = NULL;
48 static char *subject = NULL;
49 static char *err_addr = NULL;
50 static char *mailhost = NULL;
51 static char *reply_addr = NULL;
52 static int mailport = 25;
53 static char my_hostname[MAXSTRING];
57 * examine message from server
59 static void get_response(void)
63 Dmsg0(50, "Calling fgets on read socket rfp.\n");
64 while (fgets(buf, sizeof(buf), rfp)) {
65 buf[strlen(buf)-1] = 0;
66 Dmsg2(10, "%s --> %s\n", mailhost, buf);
67 if (!isdigit((int)buf[0]) || buf[0] > '3') {
68 Dmsg1(10, "Fatal malformed reply: %s\n", buf);
79 * say something to server and check the response
81 static void chat(char *fmt, ...)
86 vfprintf(sfp, fmt, ap);
87 if (debug_level >= 10) {
88 fprintf(stdout, "%s --> ", my_hostname);
89 vfprintf(stdout, fmt, ap);
94 if (debug_level >= 10) {
105 "Usage: bsmtp [-f from] [-h mailhost] [-s subject] [-c copy] [recepient ...]\n"
106 " -c set the Cc: field\n"
107 " -dnn set debug level to nn\n"
108 " -f set the From: field\n"
109 " -h use mailhost:port as the SMTP server\n"
110 " -s set the Subject: field\n"
111 " -? print this message.\n"
118 /*********************************************************************
120 * Program to send email
122 int main (int argc, char *argv[])
125 struct sockaddr_in sin;
131 my_name_is(argc, argv, "smtp");
133 while ((ch = getopt(argc, argv, "c:d:f:h:r:s:?")) != -1) {
136 Dmsg1(20, "cc=%s\n", optarg);
140 case 'd': /* set debug level */
141 debug_level = atoi(optarg);
142 if (debug_level <= 0) {
145 Dmsg1(20, "Debug level = %d\n", debug_level);
152 case 'h': /* smtp host */
153 Dmsg1(20, "host=%s\n", optarg);
154 p = strchr(optarg, ':');
162 case 's': /* subject */
163 Dmsg1(20, "subject=%s\n", optarg);
167 case 'r': /* reply address */
181 Dmsg0(0, "Fatal error: no recipient given.\n");
187 * Determine SMTP server
189 if (mailhost == NULL) {
190 if ((cp = getenv("SMTPSERVER")) != NULL) {
193 mailhost = "localhost";
198 * Find out my own host name for HELO;
199 * if possible, get the fully qualified domain name
201 if (gethostname(my_hostname, sizeof(my_hostname) - 1) < 0) {
202 Dmsg1(0, "Fatal gethostname error: ERR=%s\n", strerror(errno));
205 if ((hp = gethostbyname(my_hostname)) == NULL) {
206 Dmsg2(0, "Fatal gethostbyname for myself failed \"%s\": ERR=%s\n", my_hostname,
210 strcpy(my_hostname, hp->h_name);
211 Dmsg1(20, "My hostname is: %s\n", my_hostname);
214 * Determine from address.
216 if (from_addr == NULL) {
217 if ((pwd = getpwuid(getuid())) == 0) {
218 sprintf(buf, "userid-%d@%s", (int)getuid(), my_hostname);
220 sprintf(buf, "%s@%s", pwd->pw_name, my_hostname);
222 from_addr = bstrdup(buf);
224 Dmsg1(20, "From addr=%s\n", from_addr);
227 * Connect to smtp daemon on mailhost.
230 if ((hp = gethostbyname(mailhost)) == NULL) {
231 Dmsg2(0, "Error unknown mail host \"%s\": ERR=%s\n", mailhost,
233 if (strcasecmp(mailhost, "localhost") != 0) {
234 Dmsg0(0, "Retrying connection using \"localhost\".\n");
235 mailhost = "localhost";
241 if (hp->h_addrtype != AF_INET) {
242 Dmsg1(0, "Fatal error: Unknown address family for smtp host: %d\n", hp->h_addrtype);
245 memset((char *)&sin, 0, sizeof(sin));
246 memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
247 sin.sin_family = hp->h_addrtype;
248 sin.sin_port = htons(mailport);
249 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
250 Dmsg1(0, "Fatal socket error: ERR=%s\n", strerror(errno));
253 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
254 Dmsg1(0, "Fatal connect error: ERR=%s\n", strerror(errno));
257 Dmsg0(20, "Connected\n");
258 if ((r = dup(s)) < 0) {
259 Dmsg1(0, "Fatal dup error: ERR=%s\n", strerror(errno));
262 if ((sfp = fdopen(s, "w")) == 0) {
263 Dmsg1(0, "Fatal fdopen error: ERR=%s\n", strerror(errno));
266 if ((rfp = fdopen(r, "r")) == 0) {
267 Dmsg1(0, "Fatal fdopen error: ERR=%s\n", strerror(errno));
274 get_response(); /* banner */
275 chat("helo %s\r\n", my_hostname);
276 chat("mail from: <%s>\r\n", from_addr);
278 for (i = 0; i < argc; i++) {
279 Dmsg1(20, "rcpt to: %s\n", argv[i]);
280 chat("rcpt to: <%s>\r\n", argv[i]);
284 chat("rcpt to: <%s>\r\n", cc_addr);
290 * Send message header
292 fprintf(sfp, "From: %s\r\n", from_addr);
294 fprintf(sfp, "Subject: %s\r\n", subject);
297 fprintf(sfp, "Reply-To: %s\r\n", reply_addr);
300 fprintf(sfp, "Errors-To: %s\r\n", err_addr);
302 if ((pwd = getpwuid(getuid())) == 0) {
303 fprintf(sfp, "Sender: userid-%d@%s\r\n", (int)getuid(), my_hostname);
305 fprintf(sfp, "Sender: %s@%s\r\n", pwd->pw_name, my_hostname);
308 fprintf(sfp, "To: %s", argv[0]);
309 for (i = 1; i < argc; i++) {
310 fprintf(sfp, ",%s", argv[i]);
313 fprintf(sfp, "\r\n");
315 fprintf(sfp, "Cc: %s\r\n", cc_addr);
318 fprintf(sfp, "\r\n");
323 while (fgets(buf, sizeof(buf), stdin)) {
324 buf[strlen(buf)-1] = 0;
325 if (strcmp(buf, ".") == 0) { /* quote lone dots */
326 fprintf(sfp, "..\r\n");
327 } else { /* pass body through unchanged */
328 fprintf(sfp, "%s\r\n", buf);
333 * Send SMTP quit command
339 * Go away gracefully ...