NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
smtp.c File Reference

Send email to an SMTP server. More...

#include "config.h"
#include <netdb.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "conn/lib.h"
#include "smtp.h"
#include "lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "mutt_account.h"
#include "mutt_globals.h"
#include "mutt_socket.h"
#include <sasl/sasl.h>
#include <sasl/saslutil.h>
#include "options.h"
+ Include dependency graph for smtp.c:

Go to the source code of this file.

Data Structures

struct  SmtpAccountData
 Server connection data. More...
 
struct  SmtpAuth
 SMTP authentication multiplexor. More...
 

Macros

#define smtp_success(x)   ((x) / 100 == 2)
 
#define SMTP_READY   334
 
#define SMTP_CONTINUE   354
 
#define SMTP_ERR_READ   -2
 
#define SMTP_ERR_WRITE   -3
 
#define SMTP_ERR_CODE   -4
 
#define SMTP_PORT   25
 
#define SMTPS_PORT   465
 
#define SMTP_AUTH_SUCCESS   0
 
#define SMTP_AUTH_UNAVAIL   1
 
#define SMTP_AUTH_FAIL   -1
 
#define SMTP_CAP_NO_FLAGS   0
 No flags are set. More...
 
#define SMTP_CAP_STARTTLS   (1 << 0)
 Server supports STARTTLS command. More...
 
#define SMTP_CAP_AUTH   (1 << 1)
 Server supports AUTH command. More...
 
#define SMTP_CAP_DSN   (1 << 2)
 Server supports Delivery Status Notification. More...
 
#define SMTP_CAP_EIGHTBITMIME   (1 << 3)
 Server supports 8-bit MIME content. More...
 
#define SMTP_CAP_SMTPUTF8   (1 << 4)
 Server accepts UTF-8 strings. More...
 
#define SMTP_CAP_ALL   ((1 << 5) - 1)
 

Typedefs

typedef uint8_t SmtpCapFlags
 SMTP server capabilities. More...
 

Functions

static bool valid_smtp_code (char *buf, size_t buflen, int *n)
 Is the is a valid SMTP return code? More...
 
static int smtp_get_resp (struct SmtpAccountData *adata)
 Read a command response from the SMTP server. More...
 
static int smtp_rcpt_to (struct SmtpAccountData *adata, const struct AddressList *al)
 Set the recipient to an Address. More...
 
static int smtp_data (struct SmtpAccountData *adata, const char *msgfile)
 Send data to an SMTP server. More...
 
static const char * smtp_get_field (enum ConnAccountField field, void *gf_data)
 Get connection login credentials - Implements ConnAccount::get_field() More...
 
static int smtp_fill_account (struct SmtpAccountData *adata, struct ConnAccount *cac)
 Create ConnAccount object from SMTP Url. More...
 
static int smtp_helo (struct SmtpAccountData *adata, bool esmtp)
 Say hello to an SMTP Server. More...
 
static int smtp_auth_sasl (struct SmtpAccountData *adata, const char *mechlist)
 Authenticate using SASL. More...
 
static int smtp_auth_oauth (struct SmtpAccountData *adata, const char *method)
 Authenticate an SMTP connection using OAUTHBEARER. More...
 
static int smtp_auth_plain (struct SmtpAccountData *adata, const char *method)
 Authenticate using plain text. More...
 
static int smtp_auth_login (struct SmtpAccountData *adata, const char *method)
 Authenticate using plain text. More...
 
bool smtp_auth_is_valid (const char *authenticator)
 Check if string is a valid smtp authentication method. More...
 
static int smtp_authenticate (struct SmtpAccountData *adata)
 Authenticate to an SMTP server. More...
 
static int smtp_open (struct SmtpAccountData *adata, bool esmtp)
 Open an SMTP Connection. More...
 
int mutt_smtp_send (const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
 Send a message using SMTP. More...
 

Variables

static const struct SmtpAuth smtp_authenticators []
 Accepted authentication methods. More...
 

Detailed Description

Send email to an SMTP server.

Authors
  • Michael R. Elkins
  • Brendan Cully
  • Pietro Cerutti

This program 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 GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file smtp.c.

Macro Definition Documentation

◆ smtp_success

#define smtp_success (   x)    ((x) / 100 == 2)

Definition at line 60 of file smtp.c.

◆ SMTP_READY

#define SMTP_READY   334

Definition at line 61 of file smtp.c.

◆ SMTP_CONTINUE

#define SMTP_CONTINUE   354

Definition at line 62 of file smtp.c.

◆ SMTP_ERR_READ

#define SMTP_ERR_READ   -2

Definition at line 64 of file smtp.c.

◆ SMTP_ERR_WRITE

#define SMTP_ERR_WRITE   -3

Definition at line 65 of file smtp.c.

◆ SMTP_ERR_CODE

#define SMTP_ERR_CODE   -4

Definition at line 66 of file smtp.c.

◆ SMTP_PORT

#define SMTP_PORT   25

Definition at line 68 of file smtp.c.

◆ SMTPS_PORT

#define SMTPS_PORT   465

Definition at line 69 of file smtp.c.

◆ SMTP_AUTH_SUCCESS

#define SMTP_AUTH_SUCCESS   0

Definition at line 71 of file smtp.c.

◆ SMTP_AUTH_UNAVAIL

#define SMTP_AUTH_UNAVAIL   1

Definition at line 72 of file smtp.c.

◆ SMTP_AUTH_FAIL

#define SMTP_AUTH_FAIL   -1

Definition at line 73 of file smtp.c.

◆ SMTP_CAP_NO_FLAGS

#define SMTP_CAP_NO_FLAGS   0

No flags are set.

Definition at line 80 of file smtp.c.

◆ SMTP_CAP_STARTTLS

#define SMTP_CAP_STARTTLS   (1 << 0)

Server supports STARTTLS command.

Definition at line 81 of file smtp.c.

◆ SMTP_CAP_AUTH

#define SMTP_CAP_AUTH   (1 << 1)

Server supports AUTH command.

Definition at line 82 of file smtp.c.

◆ SMTP_CAP_DSN

#define SMTP_CAP_DSN   (1 << 2)

Server supports Delivery Status Notification.

Definition at line 83 of file smtp.c.

◆ SMTP_CAP_EIGHTBITMIME

#define SMTP_CAP_EIGHTBITMIME   (1 << 3)

Server supports 8-bit MIME content.

Definition at line 84 of file smtp.c.

◆ SMTP_CAP_SMTPUTF8

#define SMTP_CAP_SMTPUTF8   (1 << 4)

Server accepts UTF-8 strings.

Definition at line 85 of file smtp.c.

◆ SMTP_CAP_ALL

#define SMTP_CAP_ALL   ((1 << 5) - 1)

Definition at line 87 of file smtp.c.

Typedef Documentation

◆ SmtpCapFlags

typedef uint8_t SmtpCapFlags

SMTP server capabilities.

Flags, e.g. SMTP_CAP_STARTTLS

Definition at line 79 of file smtp.c.

Function Documentation

◆ valid_smtp_code()

static bool valid_smtp_code ( char *  buf,
size_t  buflen,
int *  n 
)
static

Is the is a valid SMTP return code?

Parameters
[in]bufString to check
[in]buflenLength of string
[out]nNumeric value of code
Return values
trueValid number

Definition at line 126 of file smtp.c.

127 {
128  char code[4];
129 
130  if (buflen < 4)
131  return false;
132  code[0] = buf[0];
133  code[1] = buf[1];
134  code[2] = buf[2];
135  code[3] = '\0';
136  if (mutt_str_atoi(code, n) < 0)
137  return false;
138  return true;
139 }
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_get_resp()

static int smtp_get_resp ( struct SmtpAccountData adata)
static

Read a command response from the SMTP server.

Parameters
adataSMTP Account data
Return values
0Success (2xx code) or continue (354 code)
-1Write error, or any other response code

Definition at line 147 of file smtp.c.

148 {
149  int n;
150  char buf[1024];
151 
152  do
153  {
154  n = mutt_socket_readln(buf, sizeof(buf), adata->conn);
155  if (n < 4)
156  {
157  /* read error, or no response code */
158  return SMTP_ERR_READ;
159  }
160  const char *s = buf + 4; /* Skip the response code and the space/dash */
161  size_t plen;
162 
163  if (mutt_istr_startswith(s, "8BITMIME"))
165  else if ((plen = mutt_istr_startswith(s, "AUTH ")))
166  {
167  adata->capabilities |= SMTP_CAP_AUTH;
168  FREE(&adata->auth_mechs);
169  adata->auth_mechs = mutt_str_dup(s + plen);
170  }
171  else if (mutt_istr_startswith(s, "DSN"))
172  adata->capabilities |= SMTP_CAP_DSN;
173  else if (mutt_istr_startswith(s, "STARTTLS"))
175  else if (mutt_istr_startswith(s, "SMTPUTF8"))
177 
178  if (!valid_smtp_code(buf, n, &n))
179  return SMTP_ERR_CODE;
180 
181  } while (buf[3] == '-');
182 
183  if (smtp_success(n) || (n == SMTP_CONTINUE))
184  return 0;
185 
186  mutt_error(_("SMTP session failed: %s"), buf);
187  return -1;
188 }
SmtpCapFlags capabilities
Server capabilities.
Definition: smtp.c:96
#define SMTP_CAP_STARTTLS
Server supports STARTTLS command.
Definition: smtp.c:81
#define mutt_error(...)
Definition: logging.h:88
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
#define SMTP_CAP_SMTPUTF8
Server accepts UTF-8 strings.
Definition: smtp.c:85
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
const char * auth_mechs
Allowed authorisation mechanisms.
Definition: smtp.c:95
#define SMTP_ERR_READ
Definition: smtp.c:64
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
#define smtp_success(x)
Definition: smtp.c:60
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:36
#define SMTP_ERR_CODE
Definition: smtp.c:66
static bool valid_smtp_code(char *buf, size_t buflen, int *n)
Is the is a valid SMTP return code?
Definition: smtp.c:126
#define SMTP_CONTINUE
Definition: smtp.c:62
#define SMTP_CAP_EIGHTBITMIME
Server supports 8-bit MIME content.
Definition: smtp.c:84
#define FREE(x)
Definition: memory.h:40
#define SMTP_CAP_AUTH
Server supports AUTH command.
Definition: smtp.c:82
struct Connection * conn
Server Connection.
Definition: smtp.c:97
#define SMTP_CAP_DSN
Server supports Delivery Status Notification.
Definition: smtp.c:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_rcpt_to()

static int smtp_rcpt_to ( struct SmtpAccountData adata,
const struct AddressList *  al 
)
static

Set the recipient to an Address.

Parameters
adataSMTP Account data
alAddressList to use
Return values
0Success
<0Error, e.g. SMTP_ERR_WRITE

Definition at line 197 of file smtp.c.

198 {
199  if (!al)
200  return 0;
201 
202  const char *const c_dsn_notify = cs_subset_string(adata->sub, "dsn_notify");
203 
204  struct Address *a = NULL;
205  TAILQ_FOREACH(a, al, entries)
206  {
207  /* weed out group mailboxes, since those are for display only */
208  if (!a->mailbox || a->group)
209  {
210  continue;
211  }
212  char buf[1024];
213  if ((adata->capabilities & SMTP_CAP_DSN) && c_dsn_notify)
214  snprintf(buf, sizeof(buf), "RCPT TO:<%s> NOTIFY=%s\r\n", a->mailbox, c_dsn_notify);
215  else
216  snprintf(buf, sizeof(buf), "RCPT TO:<%s>\r\n", a->mailbox);
217  if (mutt_socket_send(adata->conn, buf) == -1)
218  return SMTP_ERR_WRITE;
219  int rc = smtp_get_resp(adata);
220  if (rc != 0)
221  return rc;
222  }
223 
224  return 0;
225 }
SmtpCapFlags capabilities
Server capabilities.
Definition: smtp.c:96
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
#define SMTP_ERR_WRITE
Definition: smtp.c:65
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool group
Group mailbox?
Definition: address.h:39
struct ConfigSubset * sub
Config scope.
Definition: smtp.c:98
struct Connection * conn
Server Connection.
Definition: smtp.c:97
#define SMTP_CAP_DSN
Server supports Delivery Status Notification.
Definition: smtp.c:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_data()

static int smtp_data ( struct SmtpAccountData adata,
const char *  msgfile 
)
static

Send data to an SMTP server.

Parameters
adataSMTP Account data
msgfileFilename containing data
Return values
0Success
<0Error, e.g. SMTP_ERR_WRITE

Definition at line 234 of file smtp.c.

235 {
236  char buf[1024];
237  struct Progress *progress = NULL;
238  struct stat st;
239  int rc = SMTP_ERR_WRITE;
240  int term = 0;
241  size_t buflen = 0;
242 
243  FILE *fp = fopen(msgfile, "r");
244  if (!fp)
245  {
246  mutt_error(_("SMTP session failed: unable to open %s"), msgfile);
247  return -1;
248  }
249  stat(msgfile, &st);
250  unlink(msgfile);
251  progress = progress_new(_("Sending message..."), MUTT_PROGRESS_NET, st.st_size);
252 
253  snprintf(buf, sizeof(buf), "DATA\r\n");
254  if (mutt_socket_send(adata->conn, buf) == -1)
255  {
256  mutt_file_fclose(&fp);
257  goto done;
258  }
259  rc = smtp_get_resp(adata);
260  if (rc != 0)
261  {
262  mutt_file_fclose(&fp);
263  goto done;
264  }
265 
266  rc = SMTP_ERR_WRITE;
267  while (fgets(buf, sizeof(buf) - 1, fp))
268  {
269  buflen = mutt_str_len(buf);
270  term = buflen && buf[buflen - 1] == '\n';
271  if (term && ((buflen == 1) || (buf[buflen - 2] != '\r')))
272  snprintf(buf + buflen - 1, sizeof(buf) - buflen + 1, "\r\n");
273  if (buf[0] == '.')
274  {
275  if (mutt_socket_send_d(adata->conn, ".", MUTT_SOCK_LOG_FULL) == -1)
276  {
277  mutt_file_fclose(&fp);
278  goto done;
279  }
280  }
281  if (mutt_socket_send_d(adata->conn, buf, MUTT_SOCK_LOG_FULL) == -1)
282  {
283  mutt_file_fclose(&fp);
284  goto done;
285  }
286  progress_update(progress, ftell(fp), -1);
287  }
288  if (!term && buflen &&
289  (mutt_socket_send_d(adata->conn, "\r\n", MUTT_SOCK_LOG_FULL) == -1))
290  {
291  mutt_file_fclose(&fp);
292  goto done;
293  }
294  mutt_file_fclose(&fp);
295 
296  /* terminate the message body */
297  if (mutt_socket_send(adata->conn, ".\r\n") == -1)
298  goto done;
299 
300  rc = smtp_get_resp(adata);
301 
302 done:
303  progress_free(&progress);
304  return rc;
305 }
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define mutt_error(...)
Definition: logging.h:88
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
#define _(a)
Definition: message.h:28
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:31
A Progress Bar.
Definition: progress.c:47
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define mutt_socket_send_d(conn, buf, dbg)
Definition: mutt_socket.h:38
#define SMTP_ERR_WRITE
Definition: smtp.c:65
Progress tracks bytes, according to $net_inc
Definition: lib.h:48
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:228
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:246
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_get_field()

static const char* smtp_get_field ( enum ConnAccountField  field,
void *  gf_data 
)
static

Get connection login credentials - Implements ConnAccount::get_field()

Definition at line 310 of file smtp.c.

311 {
312  struct SmtpAccountData *adata = gf_data;
313  if (!adata)
314  return NULL;
315 
316  switch (field)
317  {
318  case MUTT_CA_LOGIN:
319  case MUTT_CA_USER:
320  {
321  const char *const c_smtp_user = cs_subset_string(adata->sub, "smtp_user");
322  return c_smtp_user;
323  }
324  case MUTT_CA_PASS:
325  {
326  const char *const c_smtp_pass = cs_subset_string(adata->sub, "smtp_pass");
327  return c_smtp_pass;
328  }
329  case MUTT_CA_OAUTH_CMD:
330  {
331  const char *const c_smtp_oauth_refresh_command =
332  cs_subset_string(adata->sub, "smtp_oauth_refresh_command");
333  return c_smtp_oauth_refresh_command;
334  }
335  case MUTT_CA_HOST:
336  default:
337  return NULL;
338  }
339 }
Password.
Definition: connaccount.h:36
Server connection data.
Definition: smtp.c:93
User name.
Definition: connaccount.h:35
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
OAuth refresh command.
Definition: connaccount.h:37
Login name.
Definition: connaccount.h:34
struct ConfigSubset * sub
Config scope.
Definition: smtp.c:98
Server name.
Definition: connaccount.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_fill_account()

static int smtp_fill_account ( struct SmtpAccountData adata,
struct ConnAccount cac 
)
static

Create ConnAccount object from SMTP Url.

Parameters
adataSMTP Account data
cacConnAccount to populate
Return values
0Success
-1Error

Definition at line 348 of file smtp.c.

349 {
350  cac->flags = 0;
351  cac->port = 0;
352  cac->type = MUTT_ACCT_TYPE_SMTP;
353  cac->service = "smtp";
354  cac->get_field = smtp_get_field;
355  cac->gf_data = adata;
356 
357  const char *const c_smtp_url = cs_subset_string(adata->sub, "smtp_url");
358 
359  struct Url *url = url_parse(c_smtp_url);
360  if (!url || ((url->scheme != U_SMTP) && (url->scheme != U_SMTPS)) ||
361  !url->host || (mutt_account_fromurl(cac, url) < 0))
362  {
363  url_free(&url);
364  mutt_error(_("Invalid SMTP URL: %s"), c_smtp_url);
365  return -1;
366  }
367 
368  if (url->scheme == U_SMTPS)
369  cac->flags |= MUTT_ACCT_SSL;
370 
371  if (cac->port == 0)
372  {
373  if (cac->flags & MUTT_ACCT_SSL)
374  cac->port = SMTPS_PORT;
375  else
376  {
377  static unsigned short SmtpPort = 0;
378  if (SmtpPort == 0)
379  {
380  struct servent *service = getservbyname("smtp", "tcp");
381  if (service)
382  SmtpPort = ntohs(service->s_port);
383  else
384  SmtpPort = SMTP_PORT;
385  mutt_debug(LL_DEBUG3, "Using default SMTP port %d\n", SmtpPort);
386  }
387  cac->port = SmtpPort;
388  }
389  }
390 
391  url_free(&url);
392  return 0;
393 }
int mutt_account_fromurl(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:43
#define mutt_error(...)
Definition: logging.h:88
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:68
static const char * smtp_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field()
Definition: smtp.c:310
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:70
#define _(a)
Definition: message.h:28
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
#define SMTP_PORT
Definition: smtp.c:68
unsigned short port
Port to connect to.
Definition: connaccount.h:57
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Function to get some login credentials.
Definition: connaccount.h:67
void * gf_data
Private data to pass to get_field()
Definition: connaccount.h:69
Url is smtps://.
Definition: url.h:44
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:58
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
char * host
Host.
Definition: url.h:73
const char * service
Name of the service, e.g. "imap".
Definition: connaccount.h:60
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
Url is smtp://.
Definition: url.h:43
Smtp Account.
Definition: mutt_account.h:39
#define SMTPS_PORT
Definition: smtp.c:69
struct ConfigSubset * sub
Config scope.
Definition: smtp.c:98
Log at debug level 3.
Definition: logging.h:42
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition: connaccount.h:46
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:59
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_helo()

static int smtp_helo ( struct SmtpAccountData adata,
bool  esmtp 
)
static

Say hello to an SMTP Server.

Parameters
adataSMTP Account data
esmtpIf true, use ESMTP
Return values
0Success
<0Error, e.g. SMTP_ERR_WRITE

Definition at line 402 of file smtp.c.

403 {
405 
406  if (!esmtp)
407  {
408  /* if TLS or AUTH are requested, use EHLO */
409  if (adata->conn->account.flags & MUTT_ACCT_USER)
410  esmtp = true;
411 #ifdef USE_SSL
412  const bool c_ssl_force_tls = cs_subset_bool(adata->sub, "ssl_force_tls");
413  const enum QuadOption c_ssl_starttls =
414  cs_subset_quad(adata->sub, "ssl_starttls");
415 
416  if (c_ssl_force_tls || (c_ssl_starttls != MUTT_NO))
417  esmtp = true;
418 #endif
419  }
420 
421  char buf[1024];
422  snprintf(buf, sizeof(buf), "%s %s\r\n", esmtp ? "EHLO" : "HELO", adata->fqdn);
423  /* XXX there should probably be a wrapper in mutt_socket.c that
424  * repeatedly calls adata->conn->write until all data is sent. This
425  * currently doesn't check for a short write. */
426  if (mutt_socket_send(adata->conn, buf) == -1)
427  return SMTP_ERR_WRITE;
428  return smtp_get_resp(adata);
429 }
SmtpCapFlags capabilities
Server capabilities.
Definition: smtp.c:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
#define MUTT_ACCT_USER
User field has been set.
Definition: connaccount.h:43
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
#define SMTP_ERR_WRITE
Definition: smtp.c:65
#define SMTP_CAP_NO_FLAGS
No flags are set.
Definition: smtp.c:80
const char * fqdn
Fully-qualified domain name.
Definition: smtp.c:99
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
struct ConfigSubset * sub
Config scope.
Definition: smtp.c:98
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:59
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_auth_sasl()

static int smtp_auth_sasl ( struct SmtpAccountData adata,
const char *  mechlist 
)
static

Authenticate using SASL.

Parameters
adataSMTP Account data
mechlistList of mechanisms to use
Return values
0Success
<0Error, e.g. SMTP_AUTH_FAIL

Definition at line 439 of file smtp.c.

440 {
441  sasl_conn_t *saslconn = NULL;
442  sasl_interact_t *interaction = NULL;
443  const char *mech = NULL;
444  const char *data = NULL;
445  unsigned int len;
446  char *buf = NULL;
447  size_t bufsize = 0;
448  int rc, saslrc;
449 
450  if (mutt_sasl_client_new(adata->conn, &saslconn) < 0)
451  return SMTP_AUTH_FAIL;
452 
453  do
454  {
455  rc = sasl_client_start(saslconn, mechlist, &interaction, &data, &len, &mech);
456  if (rc == SASL_INTERACT)
457  mutt_sasl_interact(interaction);
458  } while (rc == SASL_INTERACT);
459 
460  if ((rc != SASL_OK) && (rc != SASL_CONTINUE))
461  {
462  mutt_debug(LL_DEBUG2, "%s unavailable\n", NONULL(mech));
463  sasl_dispose(&saslconn);
464  return SMTP_AUTH_UNAVAIL;
465  }
466 
467  if (!OptNoCurses)
468  {
469  // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
470  mutt_message(_("Authenticating (%s)..."), mech);
471  }
472 
473  bufsize = MAX((len * 2), 1024);
474  buf = mutt_mem_malloc(bufsize);
475 
476  snprintf(buf, bufsize, "AUTH %s", mech);
477  if (len)
478  {
479  mutt_str_cat(buf, bufsize, " ");
480  if (sasl_encode64(data, len, buf + mutt_str_len(buf),
481  bufsize - mutt_str_len(buf), &len) != SASL_OK)
482  {
483  mutt_debug(LL_DEBUG1, "#1 error base64-encoding client response\n");
484  goto fail;
485  }
486  }
487  mutt_str_cat(buf, bufsize, "\r\n");
488 
489  do
490  {
491  if (mutt_socket_send(adata->conn, buf) < 0)
492  goto fail;
493  rc = mutt_socket_readln_d(buf, bufsize, adata->conn, MUTT_SOCK_LOG_FULL);
494  if (rc < 0)
495  goto fail;
496  if (!valid_smtp_code(buf, rc, &rc))
497  goto fail;
498 
499  if (rc != SMTP_READY)
500  break;
501 
502  if (sasl_decode64(buf + 4, strlen(buf + 4), buf, bufsize - 1, &len) != SASL_OK)
503  {
504  mutt_debug(LL_DEBUG1, "error base64-decoding server response\n");
505  goto fail;
506  }
507 
508  do
509  {
510  saslrc = sasl_client_step(saslconn, buf, len, &interaction, &data, &len);
511  if (saslrc == SASL_INTERACT)
512  mutt_sasl_interact(interaction);
513  } while (saslrc == SASL_INTERACT);
514 
515  if (len)
516  {
517  if ((len * 2) > bufsize)
518  {
519  bufsize = len * 2;
520  mutt_mem_realloc(&buf, bufsize);
521  }
522  if (sasl_encode64(data, len, buf, bufsize, &len) != SASL_OK)
523  {
524  mutt_debug(LL_DEBUG1, "#2 error base64-encoding client response\n");
525  goto fail;
526  }
527  }
528  mutt_str_copy(buf + len, "\r\n", bufsize - len);
529  } while (rc == SMTP_READY && saslrc != SASL_FAIL);
530 
531  if (smtp_success(rc))
532  {
533  mutt_sasl_setup_conn(adata->conn, saslconn);
534  FREE(&buf);
535  return SMTP_AUTH_SUCCESS;
536  }
537 
538 fail:
539  sasl_dispose(&saslconn);
540  FREE(&buf);
541  return SMTP_AUTH_FAIL;
542 }
#define NONULL(x)
Definition: string2.h:37
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define _(a)
Definition: message.h:28
int mutt_sasl_client_new(struct Connection *conn, sasl_conn_t **saslconn)
Wrapper for sasl_client_new()
Definition: sasl.c:603
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:47
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:71
void mutt_sasl_setup_conn(struct Connection *conn, sasl_conn_t *saslconn)
Set up an SASL connection.
Definition: sasl.c:734
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:31
#define MAX(a, b)
Definition: memory.h:30
Log at debug level 2.
Definition: logging.h:41
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define SMTP_READY
Definition: smtp.c:61
#define smtp_success(x)
Definition: smtp.c:60
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:385
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
#define SMTP_AUTH_UNAVAIL
Definition: smtp.c:72
Log at debug level 1.
Definition: logging.h:40
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
static bool valid_smtp_code(char *buf, size_t buflen, int *n)
Is the is a valid SMTP return code?
Definition: smtp.c:126
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:246
#define SMTP_AUTH_FAIL
Definition: smtp.c:73
int mutt_sasl_interact(sasl_interact_t *interaction)
Perform an SASL interaction with the user.
Definition: sasl.c:698
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_auth_oauth()

static int smtp_auth_oauth ( struct SmtpAccountData adata,
const char *  method 
)
static

Authenticate an SMTP connection using OAUTHBEARER.

Parameters
adataSMTP Account data
methodAuthentication method (not used)
Return values
numResult, e.g. SMTP_AUTH_SUCCESS

Definition at line 551 of file smtp.c.

552 {
553  (void) method; // This is OAUTHBEARER
554 
555  // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
556  mutt_message(_("Authenticating (%s)..."), "OAUTHBEARER");
557 
558  /* We get the access token from the smtp_oauth_refresh_command */
559  char *oauthbearer = mutt_account_getoauthbearer(&adata->conn->account);
560  if (!oauthbearer)
561  return SMTP_AUTH_FAIL;
562 
563  size_t ilen = strlen(oauthbearer) + 30;
564  char *ibuf = mutt_mem_malloc(ilen);
565  snprintf(ibuf, ilen, "AUTH OAUTHBEARER %s\r\n", oauthbearer);
566 
567  int rc = mutt_socket_send(adata->conn, ibuf);
568  FREE(&oauthbearer);
569  FREE(&ibuf);
570 
571  if (rc == -1)
572  return SMTP_AUTH_FAIL;
573  if (smtp_get_resp(adata) != 0)
574  return SMTP_AUTH_FAIL;
575 
576  return SMTP_AUTH_SUCCESS;
577 }
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
#define _(a)
Definition: message.h:28
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:71
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
char * mutt_account_getoauthbearer(struct ConnAccount *cac)
Get an OAUTHBEARER token.
Definition: connaccount.c:157
#define SMTP_AUTH_FAIL
Definition: smtp.c:73
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:

◆ smtp_auth_plain()

static int smtp_auth_plain ( struct SmtpAccountData adata,
const char *  method 
)
static

Authenticate using plain text.

Parameters
adataSMTP Account data
methodAuthentication method (not used)
Return values
0Success
<0Error, e.g. SMTP_AUTH_FAIL

Definition at line 586 of file smtp.c.

587 {
588  (void) method; // This is PLAIN
589 
590  char buf[1024];
591 
592  /* Get username and password. Bail out of any can't be retrieved. */
593  if ((mutt_account_getuser(&adata->conn->account) < 0) ||
594  (mutt_account_getpass(&adata->conn->account) < 0))
595  {
596  goto error;
597  }
598 
599  /* Build the initial client response. */
600  size_t len =
601  mutt_sasl_plain_msg(buf, sizeof(buf), "AUTH PLAIN", adata->conn->account.user,
602  adata->conn->account.user, adata->conn->account.pass);
603 
604  /* Terminate as per SMTP protocol. Bail out if there's no room left. */
605  if (snprintf(buf + len, sizeof(buf) - len, "\r\n") != 2)
606  {
607  goto error;
608  }
609 
610  /* Send request, receive response (with a check for OK code). */
611  if ((mutt_socket_send(adata->conn, buf) < 0) || smtp_get_resp(adata))
612  {
613  goto error;
614  }
615 
616  /* If we got here, auth was successful. */
617  return 0;
618 
619 error:
620  // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
621  mutt_error(_("%s authentication failed"), "SASL");
622  return -1;
623 }
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:47
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define mutt_error(...)
Definition: logging.h:88
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
char user[128]
Username.
Definition: connaccount.h:55
#define _(a)
Definition: message.h:28
size_t mutt_sasl_plain_msg(char *buf, size_t buflen, const char *cmd, const char *authz, const char *user, const char *pass)
Construct a base64 encoded SASL PLAIN message.
Definition: sasl_plain.c:55
char pass[256]
Password.
Definition: connaccount.h:56
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
Definition: connaccount.c:110
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:

◆ smtp_auth_login()

static int smtp_auth_login ( struct SmtpAccountData adata,
const char *  method 
)
static

Authenticate using plain text.

Parameters
adataSMTP Account data
methodAuthentication method (not used)
Return values
0Success
<0Error, e.g. SMTP_AUTH_FAIL

Definition at line 632 of file smtp.c.

633 {
634  (void) method; // This is LOGIN
635 
636  char b64[1024] = { 0 };
637  char buf[1024] = { 0 };
638 
639  /* Get username and password. Bail out of any can't be retrieved. */
640  if ((mutt_account_getuser(&adata->conn->account) < 0) ||
641  (mutt_account_getpass(&adata->conn->account) < 0))
642  {
643  goto error;
644  }
645 
646  /* Send the AUTH LOGIN request. */
647  if (mutt_socket_send(adata->conn, "AUTH LOGIN\r\n") < 0)
648  {
649  goto error;
650  }
651 
652  /* Read the 334 VXNlcm5hbWU6 challenge ("Username:" base64-encoded) */
653  mutt_socket_readln_d(buf, sizeof(buf), adata->conn, MUTT_SOCK_LOG_FULL);
654  if (!mutt_str_equal(buf, "334 VXNlcm5hbWU6"))
655  {
656  goto error;
657  }
658 
659  /* Send the username */
660  size_t len = snprintf(buf, sizeof(buf), "%s", adata->conn->account.user);
661  mutt_b64_encode(buf, len, b64, sizeof(b64));
662  snprintf(buf, sizeof(buf), "%s\r\n", b64);
663  if (mutt_socket_send(adata->conn, buf) < 0)
664  {
665  goto error;
666  }
667 
668  /* Read the 334 UGFzc3dvcmQ6 challenge ("Password:" base64-encoded) */
669  mutt_socket_readln_d(buf, sizeof(buf), adata->conn, MUTT_SOCK_LOG_FULL);
670  if (!mutt_str_equal(buf, "334 UGFzc3dvcmQ6"))
671  {
672  goto error;
673  }
674 
675  /* Send the password */
676  len = snprintf(buf, sizeof(buf), "%s", adata->conn->account.pass);
677  mutt_b64_encode(buf, len, b64, sizeof(b64));
678  snprintf(buf, sizeof(buf), "%s\r\n", b64);
679  if (mutt_socket_send(adata->conn, buf) < 0)
680  {
681  goto error;
682  }
683 
684  /* Check the final response */
685  if (smtp_get_resp(adata) < 0)
686  {
687  goto error;
688  }
689 
690  /* If we got here, auth was successful. */
691  return 0;
692 
693 error:
694  // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
695  mutt_error(_("%s authentication failed"), "LOGIN");
696  return -1;
697 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:47
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define mutt_error(...)
Definition: logging.h:88
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
char user[128]
Username.
Definition: connaccount.h:55
#define _(a)
Definition: message.h:28
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:31
char pass[256]
Password.
Definition: connaccount.h:56
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:88
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:246
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
Definition: connaccount.c:110
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:

◆ smtp_auth_is_valid()

bool smtp_auth_is_valid ( const char *  authenticator)

Check if string is a valid smtp authentication method.

Parameters
authenticatorAuthenticator string to check
Return values
trueArgument is a valid auth method

Validate whether an input string is an accepted smtp authentication method as defined by smtp_authenticators.

Definition at line 719 of file smtp.c.

720 {
721  for (size_t i = 0; i < mutt_array_size(smtp_authenticators); i++)
722  {
723  const struct SmtpAuth *auth = &smtp_authenticators[i];
724  if (auth->method && mutt_istr_equal(auth->method, authenticator))
725  return true;
726  }
727 
728  return false;
729 }
SMTP authentication multiplexor.
Definition: smtp.c:105
#define mutt_array_size(x)
Definition: memory.h:33
static const struct SmtpAuth smtp_authenticators[]
Accepted authentication methods.
Definition: smtp.c:702
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
const char * method
Name of authentication method supported, NULL means variable.
Definition: smtp.c:115
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_authenticate()

static int smtp_authenticate ( struct SmtpAccountData adata)
static

Authenticate to an SMTP server.

Parameters
adataSMTP Account data
Return values
0Success
<0Error, e.g. SMTP_AUTH_FAIL

Definition at line 737 of file smtp.c.

738 {
739  int r = SMTP_AUTH_UNAVAIL;
740 
741  const struct Slist *c_smtp_authenticators =
742  cs_subset_slist(adata->sub, "smtp_authenticators");
743  if (c_smtp_authenticators && (c_smtp_authenticators->count > 0))
744  {
745  mutt_debug(LL_DEBUG2, "Trying user-defined smtp_authenticators\n");
746 
747  /* Try user-specified list of authentication methods */
748  struct ListNode *np = NULL;
749  STAILQ_FOREACH(np, &c_smtp_authenticators->head, entries)
750  {
751  mutt_debug(LL_DEBUG2, "Trying method %s\n", np->data);
752 
753  for (size_t i = 0; i < mutt_array_size(smtp_authenticators); i++)
754  {
755  const struct SmtpAuth *auth = &smtp_authenticators[i];
756  if (!auth->method || mutt_istr_equal(auth->method, np->data))
757  {
758  r = auth->authenticate(adata, np->data);
759  if (r == SMTP_AUTH_SUCCESS)
760  return r;
761  }
762  }
763  }
764  }
765  else
766  {
767  /* Fall back to default: any authenticator */
768  mutt_debug(LL_DEBUG2, "Falling back to smtp_auth_sasl, if using sasl.\n");
769 
770 #ifdef USE_SASL
771  r = smtp_auth_sasl(adata, adata->auth_mechs);
772 #else
773  mutt_error(_("SMTP authentication requires SASL"));
774  r = SMTP_AUTH_UNAVAIL;
775 #endif
776  }
777 
778  if (r != SMTP_AUTH_SUCCESS)
780 
781  if (r == SMTP_AUTH_FAIL)
782  {
783  // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
784  mutt_error(_("%s authentication failed"), "SASL");
785  }
786  else if (r == SMTP_AUTH_UNAVAIL)
787  {
788  mutt_error(_("No authenticators available"));
789  }
790 
791  return (r == SMTP_AUTH_SUCCESS) ? 0 : -1;
792 }
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_error(...)
Definition: logging.h:88
SMTP authentication multiplexor.
Definition: smtp.c:105
static int smtp_auth_sasl(struct SmtpAccountData *adata, const char *mechlist)
Authenticate using SASL.
Definition: smtp.c:439
#define _(a)
Definition: message.h:28
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:71
String list.
Definition: slist.h:46
#define mutt_array_size(x)
Definition: memory.h:33
static const struct SmtpAuth smtp_authenticators[]
Accepted authentication methods.
Definition: smtp.c:702
Log at debug level 2.
Definition: logging.h:41
int(* authenticate)(struct SmtpAccountData *adata, const char *method)
Authenticate an SMTP connection.
Definition: smtp.c:113
struct ListHead head
Definition: slist.h:48
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
size_t count
Definition: slist.h:49
void mutt_account_unsetpass(struct ConnAccount *cac)
Unset ConnAccount&#39;s password.
Definition: connaccount.c:140
const char * auth_mechs
Allowed authorisation mechanisms.
Definition: smtp.c:95
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
const char * method
Name of authentication method supported, NULL means variable.
Definition: smtp.c:115
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
#define SMTP_AUTH_UNAVAIL
Definition: smtp.c:72
char * data
String.
Definition: list.h:36
A List node for strings.
Definition: list.h:34
struct ConfigSubset * sub
Config scope.
Definition: smtp.c:98
#define SMTP_AUTH_FAIL
Definition: smtp.c:73
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smtp_open()

static int smtp_open ( struct SmtpAccountData adata,
bool  esmtp 
)
static

Open an SMTP Connection.

Parameters
adataSMTP Account data
esmtpIf true, use ESMTP
Return values
0Success
-1Error

Definition at line 801 of file smtp.c.

802 {
803  int rc;
804 
805  if (mutt_socket_open(adata->conn))
806  return -1;
807 
808  /* get greeting string */
809  rc = smtp_get_resp(adata);
810  if (rc != 0)
811  return rc;
812 
813  rc = smtp_helo(adata, esmtp);
814  if (rc != 0)
815  return rc;
816 
817 #ifdef USE_SSL
818  const bool c_ssl_force_tls = cs_subset_bool(adata->sub, "ssl_force_tls");
819  const enum QuadOption c_ssl_starttls =
820  cs_subset_quad(adata->sub, "ssl_starttls");
821  enum QuadOption ans = MUTT_NO;
822  if (adata->conn->ssf != 0)
823  ans = MUTT_NO;
824  else if (c_ssl_force_tls)
825  ans = MUTT_YES;
826  else if ((adata->capabilities & SMTP_CAP_STARTTLS) &&
827  ((ans = query_quadoption(c_ssl_starttls,
828  _("Secure connection with TLS?"))) == MUTT_ABORT))
829  {
830  return -1;
831  }
832 
833  if (ans == MUTT_YES)
834  {
835  if (mutt_socket_send(adata->conn, "STARTTLS\r\n") < 0)
836  return SMTP_ERR_WRITE;
837  rc = smtp_get_resp(adata);
838  // Clear any data after the STARTTLS acknowledgement
839  mutt_socket_empty(adata->conn);
840  if (rc != 0)
841  return rc;
842 
843  if (mutt_ssl_starttls(adata->conn))
844  {
845  mutt_error(_("Could not negotiate TLS connection"));
846  return -1;
847  }
848 
849  /* re-EHLO to get authentication mechanisms */
850  rc = smtp_helo(adata, esmtp);
851  if (rc != 0)
852  return rc;
853  }
854 #endif
855 
856  if (adata->conn->account.flags & MUTT_ACCT_USER)
857  {
858  if (!(adata->capabilities & SMTP_CAP_AUTH))
859  {
860  mutt_error(_("SMTP server does not support authentication"));
861  return -1;
862  }
863 
864  return smtp_authenticate(adata);
865  }
866 
867  return 0;
868 }
SmtpCapFlags capabilities
Server capabilities.
Definition: smtp.c:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
unsigned int ssf
Security strength factor, in bits (see below)
Definition: connection.h:41
#define SMTP_CAP_STARTTLS
Server supports STARTTLS command.
Definition: smtp.c:81
#define mutt_error(...)
Definition: logging.h:88
static int smtp_helo(struct SmtpAccountData *adata, bool esmtp)
Say hello to an SMTP Server.
Definition: smtp.c:402
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
static int smtp_authenticate(struct SmtpAccountData *adata)
Authenticate to an SMTP server.
Definition: smtp.c:737
#define _(a)
Definition: message.h:28
#define MUTT_ACCT_USER
User field has been set.
Definition: connaccount.h:43
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:76
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
User aborted the question (with Ctrl-G)
Definition: quad.h:37
#define SMTP_ERR_WRITE
Definition: smtp.c:65
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition: socket.c:313
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition: gnutls.c:1167
#define SMTP_CAP_AUTH
Server supports AUTH command.
Definition: smtp.c:82
struct ConfigSubset * sub
Config scope.
Definition: smtp.c:98
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:59
struct Connection * conn
Server Connection.
Definition: smtp.c:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_smtp_send()

int mutt_smtp_send ( const struct AddressList *  from,
const struct AddressList *  to,
const struct AddressList *  cc,
const struct AddressList *  bcc,
const char *  msgfile,
bool  eightbit,
struct ConfigSubset sub 
)

Send a message using SMTP.

Parameters
fromFrom Address
toTo Address
ccCc Address
bccBcc Address
msgfileMessage to send to the server
eightbitIf true, try for an 8-bit friendly connection
subConfig Subset
Return values
0Success
-1Error

Definition at line 882 of file smtp.c.

885 {
886  struct SmtpAccountData adata = { 0 };
887  struct ConnAccount cac = { { 0 } };
888  const char *envfrom = NULL;
889  char buf[1024];
890  int rc = -1;
891 
892  adata.sub = sub;
893  adata.fqdn = mutt_fqdn(false, adata.sub);
894  if (!adata.fqdn)
895  adata.fqdn = NONULL(ShortHostname);
896 
897  const struct Address *c_envelope_from_address =
898  cs_subset_address(adata.sub, "envelope_from_address");
899 
900  /* it might be better to synthesize an envelope from from user and host
901  * but this condition is most likely arrived at accidentally */
902  if (c_envelope_from_address)
903  envfrom = c_envelope_from_address->mailbox;
904  else if (from && !TAILQ_EMPTY(from))
905  envfrom = TAILQ_FIRST(from)->mailbox;
906  else
907  {
908  mutt_error(_("No from address given"));
909  return -1;
910  }
911 
912  if (smtp_fill_account(&adata, &cac) < 0)
913  return rc;
914 
915  adata.conn = mutt_conn_find(&cac);
916  if (!adata.conn)
917  return -1;
918 
919  const char *const c_dsn_return = cs_subset_string(adata.sub, "dsn_return");
920 
921  do
922  {
923  /* send our greeting */
924  rc = smtp_open(&adata, eightbit);
925  if (rc != 0)
926  break;
927  FREE(&adata.auth_mechs);
928 
929  /* send the sender's address */
930  int len = snprintf(buf, sizeof(buf), "MAIL FROM:<%s>", envfrom);
931  if (eightbit && (adata.capabilities & SMTP_CAP_EIGHTBITMIME))
932  {
933  mutt_strn_cat(buf, sizeof(buf), " BODY=8BITMIME", 15);
934  len += 14;
935  }
936  if (c_dsn_return && (adata.capabilities & SMTP_CAP_DSN))
937  len += snprintf(buf + len, sizeof(buf) - len, " RET=%s", c_dsn_return);
938  if ((adata.capabilities & SMTP_CAP_SMTPUTF8) &&
941  {
942  snprintf(buf + len, sizeof(buf) - len, " SMTPUTF8");
943  }
944  mutt_strn_cat(buf, sizeof(buf), "\r\n", 3);
945  if (mutt_socket_send(adata.conn, buf) == -1)
946  {
947  rc = SMTP_ERR_WRITE;
948  break;
949  }
950  rc = smtp_get_resp(&adata);
951  if (rc != 0)
952  break;
953 
954  /* send the recipient list */
955  if ((rc = smtp_rcpt_to(&adata, to)) || (rc = smtp_rcpt_to(&adata, cc)) ||
956  (rc = smtp_rcpt_to(&adata, bcc)))
957  {
958  break;
959  }
960 
961  /* send the message data */
962  rc = smtp_data(&adata, msgfile);
963  if (rc != 0)
964  break;
965 
966  mutt_socket_send(adata.conn, "QUIT\r\n");
967 
968  rc = 0;
969  } while (false);
970 
971  mutt_socket_close(adata.conn);
972  FREE(&adata.conn);
973 
974  if (rc == SMTP_ERR_READ)
975  mutt_error(_("SMTP session failed: read error"));
976  else if (rc == SMTP_ERR_WRITE)
977  mutt_error(_("SMTP session failed: write error"));
978  else if (rc == SMTP_ERR_CODE)
979  mutt_error(_("Invalid server response"));
980 
981  return rc;
982 }
#define NONULL(x)
Definition: string2.h:37
SmtpCapFlags capabilities
Server capabilities.
Definition: smtp.c:96
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define mutt_error(...)
Definition: logging.h:88
char * mutt_strn_cat(char *d, size_t l, const char *s, size_t sl)
Concatenate two strings.
Definition: string.c:414
static int smtp_get_resp(struct SmtpAccountData *adata)
Read a command response from the SMTP server.
Definition: smtp.c:147
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
Definition: address.c:1512
#define SMTP_CAP_SMTPUTF8
Server accepts UTF-8 strings.
Definition: smtp.c:85
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
Server connection data.
Definition: smtp.c:93
static int smtp_rcpt_to(struct SmtpAccountData *adata, const struct AddressList *al)
Set the recipient to an Address.
Definition: smtp.c:197
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition: mutt_socket.c:89
#define SMTP_ERR_WRITE
Definition: smtp.c:65
const char * auth_mechs
Allowed authorisation mechanisms.
Definition: smtp.c:95
static int smtp_data(struct SmtpAccountData *adata, const char *msgfile)
Send data to an SMTP server.
Definition: smtp.c:234
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:46
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define SMTP_ERR_READ
Definition: smtp.c:64
const char * fqdn
Fully-qualified domain name.
Definition: smtp.c:99
Login details for a remote server.
Definition: connaccount.h:51
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:97
#define SMTP_ERR_CODE
Definition: smtp.c:66
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1187
static int smtp_fill_account(struct SmtpAccountData *adata, struct ConnAccount *cac)
Create ConnAccount object from SMTP Url.
Definition: smtp.c:348
#define SMTP_CAP_EIGHTBITMIME
Server supports 8-bit MIME content.
Definition: smtp.c:84
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:721
bool mutt_addrlist_uses_unicode(const struct AddressList *al)
Do any of a list of addresses use Unicode characters.
Definition: address.c:1532
struct ConfigSubset * sub
Config scope.
Definition: smtp.c:98
static int smtp_open(struct SmtpAccountData *adata, bool esmtp)
Open an SMTP Connection.
Definition: smtp.c:801
struct Connection * conn
Server Connection.
Definition: smtp.c:97
#define SMTP_CAP_DSN
Server supports Delivery Status Notification.
Definition: smtp.c:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ smtp_authenticators

const struct SmtpAuth smtp_authenticators[]
static
Initial value:
= {
{ smtp_auth_oauth, "oauthbearer" },
{ smtp_auth_plain, "plain" },
{ smtp_auth_login, "login" },
{ smtp_auth_sasl, NULL },
}
static int smtp_auth_sasl(struct SmtpAccountData *adata, const char *mechlist)
Authenticate using SASL.
Definition: smtp.c:439
static int smtp_auth_oauth(struct SmtpAccountData *adata, const char *method)
Authenticate an SMTP connection using OAUTHBEARER.
Definition: smtp.c:551
static int smtp_auth_login(struct SmtpAccountData *adata, const char *method)
Authenticate using plain text.
Definition: smtp.c:632
static int smtp_auth_plain(struct SmtpAccountData *adata, const char *method)
Authenticate using plain text.
Definition: smtp.c:586

Accepted authentication methods.

Definition at line 702 of file smtp.c.