3 * Send email to an SMTP server
6 * Copyright (C) 2002 Michael R. Elkins <me@mutt.org>
7 * Copyright (C) 2005-2009 Brendan Cully <brendan@kublai.com>
8 * Copyright (C) 2019 Pietro Cerutti <gahr@gahr.ch>
11 * This program is free software: you can redistribute it and/or modify it under
12 * the terms of the GNU General Public License as published by the Free Software
13 * Foundation, either version 2 of the License, or (at your option) any later
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 * You should have received a copy of the GNU General Public License along with
22 * this program. If not, see <http://www.gnu.org/licenses/>.
26 * @page smtp Send email to an SMTP server
28 * Send email to an SMTP server
31 /* This file contains code for direct SMTP delivery of email messages. */
35 #include <netinet/in.h>
42 #include "mutt/mutt.h"
43 #include "address/lib.h"
44 #include "config/lib.h"
45 #include "email/lib.h"
46 #include "conn/conn.h"
49 #include "mutt_account.h"
50 #include "mutt_socket.h"
55 #include <sasl/sasl.h>
56 #include <sasl/saslutil.h>
59 /* These Config Variables are only used in smtp.c */
60 struct Slist *C_SmtpAuthenticators; ///< Config: (smtp) List of allowed authentication methods
62 #define smtp_success(x) ((x) / 100 == 2)
63 #define SMTP_READY 334
64 #define SMTP_CONTINUE 354
66 #define SMTP_ERR_READ -2
67 #define SMTP_ERR_WRITE -3
68 #define SMTP_ERR_CODE -4
71 #define SMTPS_PORT 465
73 #define SMTP_AUTH_SUCCESS 0
74 #define SMTP_AUTH_UNAVAIL 1
75 #define SMTP_AUTH_FAIL -1
79 * typedef SmtpCapFlags - SMTP server capabilities
81 typedef uint8_t SmtpCapFlags; ///< Flags, e.g. #SMTP_CAP_STARTTLS
82 #define SMTP_CAP_NO_FLAGS 0 ///< No flags are set
83 #define SMTP_CAP_STARTTLS (1 << 0) ///< Server supports STARTTLS command
84 #define SMTP_CAP_AUTH (1 << 1) ///< Server supports AUTH command
85 #define SMTP_CAP_DSN (1 << 2) ///< Server supports Delivery Status Notification
86 #define SMTP_CAP_EIGHTBITMIME (1 << 3) ///< Server supports 8-bit MIME content
87 #define SMTP_CAP_SMTPUTF8 (1 << 4) ///< Server accepts UTF-8 strings
89 #define SMTP_CAP_ALL ((1 << 5) - 1)
92 static char *AuthMechs = NULL;
93 static SmtpCapFlags Capabilities;
96 * valid_smtp_code - Is the is a valid SMTP return code?
97 * @param[in] buf String to check
98 * @param[in] buflen Length of string
99 * @param[out] n Numeric value of code
100 * @retval true Valid number
102 static bool valid_smtp_code(char *buf, size_t buflen, int *n)
112 if (mutt_str_atoi(code, n) < 0)
118 * smtp_get_resp - Read a command response from the SMTP server
119 * @param conn SMTP connection
120 * @retval 0 Success (2xx code) or continue (354 code)
121 * @retval -1 Write error, or any other response code
123 static int smtp_get_resp(struct Connection *conn)
130 n = mutt_socket_readln(buf, sizeof(buf), conn);
133 /* read error, or no response code */
134 return SMTP_ERR_READ;
136 const char *s = buf + 4; /* Skip the response code and the space/dash */
139 if (mutt_str_startswith(s, "8BITMIME", CASE_IGNORE))
140 Capabilities |= SMTP_CAP_EIGHTBITMIME;
141 else if ((plen = mutt_str_startswith(s, "AUTH ", CASE_IGNORE)))
143 Capabilities |= SMTP_CAP_AUTH;
145 AuthMechs = mutt_str_strdup(s + plen);
147 else if (mutt_str_startswith(s, "DSN", CASE_IGNORE))
148 Capabilities |= SMTP_CAP_DSN;
149 else if (mutt_str_startswith(s, "STARTTLS", CASE_IGNORE))
150 Capabilities |= SMTP_CAP_STARTTLS;
151 else if (mutt_str_startswith(s, "SMTPUTF8", CASE_IGNORE))
152 Capabilities |= SMTP_CAP_SMTPUTF8;
154 if (!valid_smtp_code(buf, n, &n))
155 return SMTP_ERR_CODE;
157 } while (buf[3] == '-');
159 if (smtp_success(n) || (n == SMTP_CONTINUE))
162 mutt_error(_("SMTP session failed: %s"), buf);
167 * smtp_rcpt_to - Set the recipient to an Address
168 * @param conn Server Connection
169 * @param al AddressList to use
171 * @retval <0 Error, e.g. #SMTP_ERR_WRITE
173 static int smtp_rcpt_to(struct Connection *conn, const struct AddressList *al)
178 struct Address *a = NULL;
179 TAILQ_FOREACH(a, al, entries)
181 /* weed out group mailboxes, since those are for display only */
182 if (!a->mailbox || a->group)
187 if ((Capabilities & SMTP_CAP_DSN) && C_DsnNotify)
188 snprintf(buf, sizeof(buf), "RCPT TO:<%s> NOTIFY=%s\r\n", a->mailbox, C_DsnNotify);
190 snprintf(buf, sizeof(buf), "RCPT TO:<%s>\r\n", a->mailbox);
191 if (mutt_socket_send(conn, buf) == -1)
192 return SMTP_ERR_WRITE;
193 int rc = smtp_get_resp(conn);
202 * smtp_data - Send data to an SMTP server
203 * @param conn SMTP Connection
204 * @param msgfile Filename containing data
206 * @retval <0 Error, e.g. #SMTP_ERR_WRITE
208 static int smtp_data(struct Connection *conn, const char *msgfile)
211 struct Progress progress;
216 FILE *fp = fopen(msgfile, "r");
219 mutt_error(_("SMTP session failed: unable to open %s"), msgfile);
224 mutt_progress_init(&progress, _("Sending message..."), MUTT_PROGRESS_NET, st.st_size);
226 snprintf(buf, sizeof(buf), "DATA\r\n");
227 if (mutt_socket_send(conn, buf) == -1)
229 mutt_file_fclose(&fp);
230 return SMTP_ERR_WRITE;
232 rc = smtp_get_resp(conn);
235 mutt_file_fclose(&fp);
239 while (fgets(buf, sizeof(buf) - 1, fp))
241 buflen = mutt_str_strlen(buf);
242 term = buflen && buf[buflen - 1] == '\n';
243 if (term && ((buflen == 1) || (buf[buflen - 2] != '\r')))
244 snprintf(buf + buflen - 1, sizeof(buf) - buflen + 1, "\r\n");
247 if (mutt_socket_send_d(conn, ".", MUTT_SOCK_LOG_FULL) == -1)
249 mutt_file_fclose(&fp);
250 return SMTP_ERR_WRITE;
253 if (mutt_socket_send_d(conn, buf, MUTT_SOCK_LOG_FULL) == -1)
255 mutt_file_fclose(&fp);
256 return SMTP_ERR_WRITE;
258 mutt_progress_update(&progress, ftell(fp), -1);
260 if (!term && buflen && (mutt_socket_send_d(conn, "\r\n", MUTT_SOCK_LOG_FULL) == -1))
262 mutt_file_fclose(&fp);
263 return SMTP_ERR_WRITE;
265 mutt_file_fclose(&fp);
267 /* terminate the message body */
268 if (mutt_socket_send(conn, ".\r\n") == -1)
269 return SMTP_ERR_WRITE;
271 rc = smtp_get_resp(conn);
279 * address_uses_unicode - Do any addresses use Unicode
280 * @param a Address list to check
281 * @retval true if any of the string of addresses use 8-bit characters
283 static bool address_uses_unicode(const char *a)
290 if ((unsigned char) *a & (1 << 7))
299 * addresses_use_unicode - Do any of a list of addresses use Unicode
300 * @param al Address list to check
301 * @retval true if any use 8-bit characters
303 static bool addresses_use_unicode(const struct AddressList *al)
310 struct Address *a = NULL;
311 TAILQ_FOREACH(a, al, entries)
313 if (a->mailbox && !a->group && address_uses_unicode(a->mailbox))
320 * smtp_fill_account - Create ConnAccount object from SMTP Url
321 * @param account ConnAccount to populate
325 static int smtp_fill_account(struct ConnAccount *account)
329 account->type = MUTT_ACCT_TYPE_SMTP;
331 struct Url *url = url_parse(C_SmtpUrl);
332 if (!url || ((url->scheme != U_SMTP) && (url->scheme != U_SMTPS)) ||
333 !url->host || (mutt_account_fromurl(account, url) < 0))
336 mutt_error(_("Invalid SMTP URL: %s"), C_SmtpUrl);
340 if (url->scheme == U_SMTPS)
341 account->flags |= MUTT_ACCT_SSL;
343 if (account->port == 0)
345 if (account->flags & MUTT_ACCT_SSL)
346 account->port = SMTPS_PORT;
349 static unsigned short SmtpPort = 0;
352 struct servent *service = getservbyname("smtp", "tcp");
354 SmtpPort = ntohs(service->s_port);
356 SmtpPort = SMTP_PORT;
357 mutt_debug(LL_DEBUG3, "Using default SMTP port %d\n", SmtpPort);
359 account->port = SmtpPort;
368 * smtp_helo - Say hello to an SMTP Server
369 * @param conn SMTP Connection
370 * @param esmtp If true, use ESMTP
372 * @retval <0 Error, e.g. #SMTP_ERR_WRITE
374 static int smtp_helo(struct Connection *conn, bool esmtp)
380 /* if TLS or AUTH are requested, use EHLO */
381 if (conn->account.flags & MUTT_ACCT_USER)
384 if (C_SslForceTls || (C_SslStarttls != MUTT_NO))
389 const char *fqdn = mutt_fqdn(false);
391 fqdn = NONULL(ShortHostname);
394 snprintf(buf, sizeof(buf), "%s %s\r\n", esmtp ? "EHLO" : "HELO", fqdn);
395 /* XXX there should probably be a wrapper in mutt_socket.c that
396 * repeatedly calls conn->write until all data is sent. This
397 * currently doesn't check for a short write. */
398 if (mutt_socket_send(conn, buf) == -1)
399 return SMTP_ERR_WRITE;
400 return smtp_get_resp(conn);
405 * smtp_auth_sasl - Authenticate using SASL
406 * @param conn SMTP Connection
407 * @param mechlist List of mechanisms to use
409 * @retval <0 Error, e.g. #SMTP_AUTH_FAIL
411 static int smtp_auth_sasl(struct Connection *conn, const char *mechlist)
413 sasl_conn_t *saslconn = NULL;
414 sasl_interact_t *interaction = NULL;
415 const char *mech = NULL;
416 const char *data = NULL;
422 if (mutt_sasl_client_new(conn, &saslconn) < 0)
423 return SMTP_AUTH_FAIL;
427 rc = sasl_client_start(saslconn, mechlist, &interaction, &data, &len, &mech);
428 if (rc == SASL_INTERACT)
429 mutt_sasl_interact(interaction);
430 } while (rc == SASL_INTERACT);
432 if ((rc != SASL_OK) && (rc != SASL_CONTINUE))
434 mutt_debug(LL_DEBUG2, "%s unavailable\n", mech);
435 sasl_dispose(&saslconn);
436 return SMTP_AUTH_UNAVAIL;
440 mutt_message(_("Authenticating (%s)..."), mech);
442 bufsize = MAX((len * 2), 1024);
443 buf = mutt_mem_malloc(bufsize);
445 snprintf(buf, bufsize, "AUTH %s", mech);
448 mutt_str_strcat(buf, bufsize, " ");
449 if (sasl_encode64(data, len, buf + mutt_str_strlen(buf),
450 bufsize - mutt_str_strlen(buf), &len) != SASL_OK)
452 mutt_debug(LL_DEBUG1, "#1 error base64-encoding client response\n");
456 mutt_str_strcat(buf, bufsize, "\r\n");
460 if (mutt_socket_send(conn, buf) < 0)
462 rc = mutt_socket_readln_d(buf, bufsize, conn, MUTT_SOCK_LOG_FULL);
465 if (!valid_smtp_code(buf, rc, &rc))
468 if (rc != SMTP_READY)
471 if (sasl_decode64(buf + 4, strlen(buf + 4), buf, bufsize - 1, &len) != SASL_OK)
473 mutt_debug(LL_DEBUG1, "error base64-decoding server response\n");
479 saslrc = sasl_client_step(saslconn, buf, len, &interaction, &data, &len);
480 if (saslrc == SASL_INTERACT)
481 mutt_sasl_interact(interaction);
482 } while (saslrc == SASL_INTERACT);
486 if ((len * 2) > bufsize)
489 mutt_mem_realloc(&buf, bufsize);
491 if (sasl_encode64(data, len, buf, bufsize, &len) != SASL_OK)
493 mutt_debug(LL_DEBUG1, "#2 error base64-encoding client response\n");
497 mutt_str_strfcpy(buf + len, "\r\n", bufsize - len);
498 } while (rc == SMTP_READY && saslrc != SASL_FAIL);
500 if (smtp_success(rc))
502 mutt_sasl_setup_conn(conn, saslconn);
504 return SMTP_AUTH_SUCCESS;
508 sasl_dispose(&saslconn);
510 return SMTP_AUTH_FAIL;
515 * smtp_auth_oauth - Authenticate an SMTP connection using OAUTHBEARER
516 * @param conn Connection info
517 * @retval num Result, e.g. #SMTP_AUTH_SUCCESS
519 static int smtp_auth_oauth(struct Connection *conn)
521 mutt_message(_("Authenticating (OAUTHBEARER)..."));
523 /* We get the access token from the smtp_oauth_refresh_command */
524 char *oauthbearer = mutt_account_getoauthbearer(&conn->account);
526 return SMTP_AUTH_FAIL;
528 size_t ilen = strlen(oauthbearer) + 30;
529 char *ibuf = mutt_mem_malloc(ilen);
530 snprintf(ibuf, ilen, "AUTH OAUTHBEARER %s\r\n", oauthbearer);
532 int rc = mutt_socket_send(conn, ibuf);
537 return SMTP_AUTH_FAIL;
538 if (smtp_get_resp(conn) != 0)
539 return SMTP_AUTH_FAIL;
541 return SMTP_AUTH_SUCCESS;
545 * smtp_auth_plain - Authenticate using plain text
546 * @param conn SMTP Connection
548 * @retval <0 Error, e.g. #SMTP_AUTH_FAIL
550 static int smtp_auth_plain(struct Connection *conn)
554 /* Get username and password. Bail out of any can't be retrieved. */
555 if ((mutt_account_getuser(&conn->account) < 0) ||
556 (mutt_account_getpass(&conn->account) < 0))
561 /* Build the initial client response. */
562 size_t len = mutt_sasl_plain_msg(buf, sizeof(buf), "AUTH PLAIN", conn->account.user,
563 conn->account.user, conn->account.pass);
565 /* Terminate as per SMTP protocol. Bail out if there's no room left. */
566 if (snprintf(buf + len, sizeof(buf) - len, "\r\n") != 2)
571 /* Send request, receive response (with a check for OK code). */
572 if ((mutt_socket_send(conn, buf) < 0) || smtp_get_resp(conn))
577 /* If we got here, auth was successful. */
581 mutt_error(_("SASL authentication failed"));
586 * smtp_auth - Authenticate to an SMTP server
587 * @param conn SMTP Connection
589 * @retval <0 Error, e.g. #SMTP_AUTH_FAIL
591 static int smtp_auth(struct Connection *conn)
593 int r = SMTP_AUTH_UNAVAIL;
595 if (C_SmtpAuthenticators)
597 struct ListNode *np = NULL;
598 STAILQ_FOREACH(np, &C_SmtpAuthenticators->head, entries)
600 mutt_debug(LL_DEBUG2, "Trying method %s\n", np->data);
602 if (strcmp(np->data, "oauthbearer") == 0)
604 r = smtp_auth_oauth(conn);
606 else if (strcmp(np->data, "plain") == 0)
608 r = smtp_auth_plain(conn);
613 r = smtp_auth_sasl(conn, np->data);
615 mutt_error(_("SMTP authentication method %s requires SASL"), np->data);
620 if ((r == SMTP_AUTH_FAIL) && (C_SmtpAuthenticators->count > 1))
622 mutt_error(_("%s authentication failed, trying next method"), np->data);
624 else if (r != SMTP_AUTH_UNAVAIL)
631 r = smtp_auth_sasl(conn, AuthMechs);
633 mutt_error(_("SMTP authentication requires SASL"));
634 r = SMTP_AUTH_UNAVAIL;
638 if (r != SMTP_AUTH_SUCCESS)
639 mutt_account_unsetpass(&conn->account);
641 if (r == SMTP_AUTH_FAIL)
643 mutt_error(_("SASL authentication failed"));
645 else if (r == SMTP_AUTH_UNAVAIL)
647 mutt_error(_("No authenticators available"));
650 return (r == SMTP_AUTH_SUCCESS) ? 0 : -1;
654 * smtp_open - Open an SMTP Connection
655 * @param conn SMTP Connection
656 * @param esmtp If true, use ESMTP
660 static int smtp_open(struct Connection *conn, bool esmtp)
664 if (mutt_socket_open(conn))
667 /* get greeting string */
668 rc = smtp_get_resp(conn);
672 rc = smtp_helo(conn, esmtp);
677 enum QuadOption ans = MUTT_NO;
680 else if (C_SslForceTls)
682 else if ((Capabilities & SMTP_CAP_STARTTLS) &&
683 ((ans = query_quadoption(C_SslStarttls,
684 _("Secure connection with TLS?"))) == MUTT_ABORT))
691 if (mutt_socket_send(conn, "STARTTLS\r\n") < 0)
692 return SMTP_ERR_WRITE;
693 rc = smtp_get_resp(conn);
697 if (mutt_ssl_starttls(conn))
699 mutt_error(_("Could not negotiate TLS connection"));
703 /* re-EHLO to get authentication mechanisms */
704 rc = smtp_helo(conn, esmtp);
710 if (conn->account.flags & MUTT_ACCT_USER)
712 if (!(Capabilities & SMTP_CAP_AUTH))
714 mutt_error(_("SMTP server does not support authentication"));
718 return smtp_auth(conn);
725 * mutt_smtp_send - Send a message using SMTP
726 * @param from From Address
727 * @param to To Address
728 * @param cc Cc Address
729 * @param bcc Bcc Address
730 * @param msgfile Message to send to the server
731 * @param eightbit If true, try for an 8-bit friendly connection
735 int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to,
736 const struct AddressList *cc, const struct AddressList *bcc,
737 const char *msgfile, bool eightbit)
739 struct Connection *conn = NULL;
740 struct ConnAccount account;
741 const char *envfrom = NULL;
745 /* it might be better to synthesize an envelope from from user and host
746 * but this condition is most likely arrived at accidentally */
747 if (C_EnvelopeFromAddress)
748 envfrom = C_EnvelopeFromAddress->mailbox;
749 else if (from && !TAILQ_EMPTY(from))
750 envfrom = TAILQ_FIRST(from)->mailbox;
753 mutt_error(_("No from address given"));
757 if (smtp_fill_account(&account) < 0)
760 conn = mutt_conn_find(NULL, &account);
766 /* send our greeting */
767 rc = smtp_open(conn, eightbit);
772 /* send the sender's address */
773 int len = snprintf(buf, sizeof(buf), "MAIL FROM:<%s>", envfrom);
774 if (eightbit && (Capabilities & SMTP_CAP_EIGHTBITMIME))
776 mutt_str_strncat(buf, sizeof(buf), " BODY=8BITMIME", 15);
779 if (C_DsnReturn && (Capabilities & SMTP_CAP_DSN))
780 len += snprintf(buf + len, sizeof(buf) - len, " RET=%s", C_DsnReturn);
781 if ((Capabilities & SMTP_CAP_SMTPUTF8) &&
782 (address_uses_unicode(envfrom) || addresses_use_unicode(to) ||
783 addresses_use_unicode(cc) || addresses_use_unicode(bcc)))
785 snprintf(buf + len, sizeof(buf) - len, " SMTPUTF8");
787 mutt_str_strncat(buf, sizeof(buf), "\r\n", 3);
788 if (mutt_socket_send(conn, buf) == -1)
793 rc = smtp_get_resp(conn);
797 /* send the recipient list */
798 if ((rc = smtp_rcpt_to(conn, to)) || (rc = smtp_rcpt_to(conn, cc)) ||
799 (rc = smtp_rcpt_to(conn, bcc)))
804 /* send the message data */
805 rc = smtp_data(conn, msgfile);
809 mutt_socket_send(conn, "QUIT\r\n");
814 mutt_socket_close(conn);
817 if (rc == SMTP_ERR_READ)
818 mutt_error(_("SMTP session failed: read error"));
819 else if (rc == SMTP_ERR_WRITE)
820 mutt_error(_("SMTP session failed: write error"));
821 else if (rc == SMTP_ERR_CODE)
822 mutt_error(_("Invalid server response"));