[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[msmtp-users] Generating a From: header if it is missing



Hi everyone,

currently msmtp never generates a From: header. However,
sendmail/postfix/exim/ssmtp and probably every other MTA and MTA
replacement generate such a header if none is present in the mail.

There are programs that expect this behavior, and msmtp claims
compatibility with the sendmail interface, so it should do the same.

My current idea is to use the envelope-from address that msmtp already
knows, and add a From: header with this address as the last header line
if no From: header was seen. That way, msmtp can re-use the existing
functionality of 'auto_from'/'maildomain' (to generate an address) and
'from' (to set an address explicitly).

This is a change in behavior from previous versions, but I expect no
problems: in most use cases, mails should already have a From: header,
so nothing changes there. In the remaining use cases, not having a
From: header is a bug, since per RFC 2822 every mail *must* contain a
From: header.

The attached patch implements this, and also supports the sendmail -F
option for setting a full name for the From: header.

Do you see problems with this approach? Are there alternative
suggestions?

Regards,
Martin
diff --git a/src/msmtp.c b/src/msmtp.c
index 315e7f9..79b9ecd 100644
--- a/src/msmtp.c
+++ b/src/msmtp.c
@@ -984,7 +984,7 @@ error_exit:
  * msmtp_read_addresses()
  *
  * Copies the headers of the mail from 'mailf' to a temporary file 'tmpfile',
- * including the blank line that separates the header from the body of the mail.
+ * excluding the blank line that separates the header from the body of the mail.
  *
  * If 'recipients' is not NULL: extracts all recipients from the To, Cc, and Bcc
  * headers and adds them to 'recipients'. If Resent-* headers are present, all
@@ -1459,7 +1459,15 @@ int msmtp_read_addresses(FILE *mailf, FILE *tmpfile,
             }
         }
 
-        if (tmpfile && c != EOF && fputc(c, tmpfile) == EOF)
+        if (state == STATE_HEADERS_END)
+        {
+            if (c != EOF && ungetc(c, mailf) == EOF)
+            {
+                *errstr = xasprintf(_("input error while reading the mail"));
+                goto error_exit;
+            }
+        }
+        else if (tmpfile && c != EOF && fputc(c, tmpfile) == EOF)
         {
             *errstr = xasprintf(_("cannot write mail headers to temporary "
                         "file: output error"));
@@ -2424,6 +2432,8 @@ typedef struct
     account_t *cmdline_account;
     const char *account_id;
     char *user_conffile;
+    /* additional information */
+    char *full_name;
     /* the list of recipients */
     list_t *recipients;
 } msmtp_cmdline_conf_t;
@@ -2554,6 +2564,8 @@ int msmtp_cmdline(msmtp_cmdline_conf_t *conf, int argc, char *argv[])
     conf->cmdline_account = account_new(NULL, NULL);
     conf->account_id = NULL;
     conf->user_conffile = NULL;
+    /* additional information */
+    conf->full_name = NULL;
     /* the recipients */
     conf->recipients = NULL;
 
@@ -3147,9 +3159,13 @@ int msmtp_cmdline(msmtp_cmdline_conf_t *conf, int argc, char *argv[])
                 }
                 break;
 
+            case 'F':
+                free(conf->full_name);
+                conf->full_name = xstrdup(optarg);
+                break;
+
             case 'A':
             case 'B':
-            case 'F':
             case 'G':
             case 'h':
             case 'i':
@@ -3588,6 +3604,7 @@ int main(int argc, char *argv[])
 #endif
     /* needed to extract addresses from headers */
     FILE *tmpfile = NULL;
+    int have_from_header = 0;
 
 
     /* Avoid the side effects of text mode interpretations on DOS systems. */
@@ -3636,8 +3653,9 @@ int main(int argc, char *argv[])
         goto exit;
     }
     /* Read recipients and/or the envelope from address from the mail. */
-    if (conf.sendmail && (conf.read_recipients || conf.read_envelope_from))
+    if (conf.sendmail)
     {
+        char *envelope_from = NULL;
         if (!(tmpfile = tempfile(PACKAGE_NAME)))
         {
             print_error(_("cannot create temporary file: %s"),
@@ -3648,24 +3666,20 @@ int main(int argc, char *argv[])
         if ((error_code = msmtp_read_addresses(stdin, tmpfile,
                         conf.read_recipients
                             ? list_last(conf.recipients) : NULL,
-                        conf.read_envelope_from
-                            ? &(conf.cmdline_account->from) : NULL,
-                        &errstr)) != EX_OK)
+                        &envelope_from, &errstr)) != EX_OK)
         {
             print_error("%s", msmtp_sanitize_string(errstr));
             goto exit;
         }
-        if (conf.read_envelope_from && (conf.pretend || conf.debug))
-        {
-            printf(_("envelope from address extracted from mail: %s\n"),
-                    conf.cmdline_account->from);
-        }
-        if (fseeko(tmpfile, 0, SEEK_SET) != 0)
+        have_from_header = (envelope_from ? 1 : 0);
+        if (conf.read_envelope_from)
         {
-            print_error(_("cannot rewind temporary file: %s"),
-                    msmtp_sanitize_string(strerror(errno)));
-            error_code = EX_IOERR;
-            goto exit;
+            conf.cmdline_account->from = envelope_from;
+            if (conf.pretend || conf.debug)
+            {
+                printf(_("envelope from address extracted from mail: %s\n"),
+                        conf.cmdline_account->from);
+            }
         }
     }
     /* check the list of recipients */
@@ -3931,6 +3945,25 @@ int main(int argc, char *argv[])
     /* do the work */
     if (conf.sendmail)
     {
+        if (!have_from_header)
+        {
+            if (conf.full_name)
+            {
+                fprintf(tmpfile, "From: %s <%s>\n",
+                        conf.full_name, account->from);
+            }
+            else
+            {
+                fprintf(tmpfile, "From: %s\n", account->from);
+            }
+        }
+        if (fseeko(tmpfile, 0, SEEK_SET) != 0)
+        {
+            print_error(_("cannot rewind temporary file: %s"),
+                    msmtp_sanitize_string(strerror(errno)));
+            error_code = EX_IOERR;
+            goto exit;
+        }
         if ((error_code = msmtp_sendmail(account, conf.recipients,
                         stdin, tmpfile, conf.debug, &mailsize,
                         &lmtp_errstrs, &lmtp_error_msgs,