<<< Date Index >>>     <<< Thread Index >>>

[PATCH] MDN [Re: How to send a return receipt]



[moved from mutt-users]

* On 2007.10.11, in <20071011185933.GB4215@xxxxxxxxxx>,
*       "Patrick Schoenfeld" <schoenfeld@xxxxxxxxxxxxxxxxx> wrote: 
> 
> Hm. I will look for that patch. Any ideas why this has not been integrated 
> into
> the main development tree of mutt?

I don't know.  Possibly some combination of the things others are saying,
although we support other features which are not universally agreed to be
good.

I'm not too keen on MDNs myself, but if it works for your business process
and you're the one who wants to send them (not request them), who am I to
argue?

I had a copy of Werner's patch on my system.  It was patch rev 3, last
updated for 1.5.8.  I've updated it for hg tip (f467353f5657), and added
support for sending via direct SMTP as an alternative to sendmail.  The
patch doesn't include documentation, but here's some quick stuff:

There are three configuration variables:
* mdn_enable
  boolean
  When set, the message disposition notification support (RFC-2298)
  is enabled.  This shows an extra menu entry in the composer menu and
  enables all the other MDN features.  Keep it disabled to prevent any
  disposition notifications to be send.

* mdn_confirm
  boolean
  When set, a confirmation to send a message disposition
  notification is always requested.  When unset, a confirmation is
  only requested for suspect messages as demanded by RFC-2298.

* mh_seq_mdnsent
  string
  The name of the MH sequence used to mark messages for whom a
  message disposition notice has already been sent.

There are two bindings for the Compose menu:
* ESC n 
  edit Display-Notification-To header
* ESC N 
  switch DNT header

There are three configuration commands, too:
* mdn_allow
* mdn_deny
* mdn_dnt_defaults

I can make obvious guesses what these are for, but with a little
experimentation I wasn't able to get them or the bindings to do
anything.  I didn't have much time to spend on it, though, so maybe
someone else wants to try.

Patch attached.

-- 
 -D.    dgc@xxxxxxxxxxxx    NSIT    University of Chicago
 "Polka music needs to prevail."   John Ziobrowski, Polka America Corporation
diff -r f467353f5657 OPS
--- a/OPS       Sat Mar 31 18:50:39 2007 -0700
+++ b/OPS       Fri Oct 12 11:41:36 2007 -0500
@@ -27,6 +27,7 @@ OP_COMPOSE_EDIT_MESSAGE "edit the messag
 OP_COMPOSE_EDIT_MESSAGE "edit the message"
 OP_COMPOSE_EDIT_MIME "edit attachment using mailcap entry"
 OP_COMPOSE_EDIT_REPLY_TO "edit the Reply-To field"
+OP_COMPOSE_EDIT_DNT "edit the Disposition-Notification-To field"
 OP_COMPOSE_EDIT_SUBJECT "edit the subject of this message"
 OP_COMPOSE_EDIT_TO "edit the TO list"
 OP_CREATE_MAILBOX "create a new mailbox (IMAP only)"
@@ -42,6 +43,7 @@ OP_COMPOSE_TOGGLE_UNLINK "toggle whether
 OP_COMPOSE_TOGGLE_UNLINK "toggle whether to delete file after sending it"
 OP_COMPOSE_UPDATE_ENCODING "update an attachment's encoding info"
 OP_COMPOSE_WRITE_MESSAGE "write the message to a folder"
+OP_COMPOSE_SWITCH_DNT "switch between Disposition-Notification-To defaults"
 OP_COPY_MESSAGE "copy a message to a file/mailbox"
 OP_CREATE_ALIAS "create an alias from a message sender"
 OP_CURRENT_BOTTOM "move entry to bottom of screen"
diff -r f467353f5657 PATCHES
--- a/PATCHES   Sat Mar 31 18:50:39 2007 -0700
+++ b/PATCHES   Fri Oct 12 11:41:36 2007 -0500
@@ -0,0 +1,1 @@
+patch-1.5.8.g10.mdn.3
diff -r f467353f5657 alias.c
--- a/alias.c   Sat Mar 31 18:50:39 2007 -0700
+++ b/alias.c   Fri Oct 12 11:41:36 2007 -0500
@@ -140,6 +140,7 @@ void mutt_expand_aliases_env (ENVELOPE *
   env->cc = mutt_expand_aliases (env->cc);
   env->bcc = mutt_expand_aliases (env->bcc);
   env->reply_to = mutt_expand_aliases (env->reply_to);
+  env->dnt = mutt_expand_aliases (env->dnt);
   env->mail_followup_to = mutt_expand_aliases (env->mail_followup_to);
 }
 
diff -r f467353f5657 commands.c
--- a/commands.c        Sat Mar 31 18:50:39 2007 -0700
+++ b/commands.c        Fri Oct 12 11:41:36 2007 -0500
@@ -32,6 +32,7 @@
 #include "pager.h"
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
+#include "rfc2047.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -55,6 +56,311 @@
 /* The folder the user last saved to.  Used by ci_save_message() */
 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
 
+static int is_in_mdn_list (ADDRESS *addr, LIST *p)
+{
+  if (addr->mailbox)
+  {
+    for (;p; p = p->next)
+      if (!mutt_strncasecmp (addr->mailbox, p->data, mutt_strlen (p->data)))
+       return 1;
+  }
+  return 0;
+}
+
+/* Compare 2 addresses.  Thisactually should do a case-insensitive
+   compare on the mailbox part (according to rfc-2298) but we ignore
+   that because case sensitive mailboxes are not common.
+   
+   FIXME: There is a similar but static function in send.c: mutt_addrcmp.
+ */
+static int address_compare (ADDRESS *a, ADDRESS *b)
+{
+  if (!a->mailbox || !b->mailbox)
+    return-1;
+  return ascii_strcasecmp (a->mailbox, b->mailbox);
+}
+
+static void write_address (FILE *fp, const char *tag, const char *prefix,
+                           ADDRESS *a, int qualify)
+{
+  const char *fqdn = mutt_fqdn (1);
+  char buffer[STRING];
+  ADDRESS *aa;
+
+  aa = rfc822_cpy_adr (a);
+  if (fqdn && qualify)
+    rfc822_qualify (aa, fqdn);
+  rfc2047_encode_adrlist (aa, tag);
+  *buffer = 0;
+  rfc822_write_address (buffer, sizeof (buffer), aa, 1);
+  rfc822_free_address (&aa);
+
+  fprintf (fp, "%s: %s%s\n", tag, prefix, buffer);
+}
+
+
+
+
+/* Record that the MDN as already been sent. */
+static void mark_mdn_done (HEADER *cur)
+{
+  /* Hmmm: How should this be done.  IMHO the New Message mark should
+     be sufficient but it is not exactly what we want: IF one select
+     "ignore for now" the message will be flaged as old but the MDN
+     was not sent and the next time it gets displayed, there won't be
+     an indication whether it should be sent or not.  Also automatic
+     tools won't be able to detect that status. */
+  mutt_set_flag (Context, cur, M_MDNSENT, 1);
+}
+
+/* Construct a Message Disposition Notiifcation and send it out. */
+static void mutt_send_mdn (HEADER *cur, int confirmed, ADDRESS *dnt)
+{
+  char fnamebuf[LONG_STRING];
+  FILE *fp;
+  HEADER *msg;
+  BODY *t;
+  char current_date_buf[SHORT_STRING], *current_date;
+  ADDRESS *addr;
+
+  mutt_make_date (current_date_buf, sizeof (current_date_buf));
+  current_date = current_date_buf;
+  current_date += strncmp (current_date_buf, "Date: ",6)? 0:6;
+  if (*current_date && current_date[strlen(current_date)-1] =='\n')
+    current_date[strlen(current_date)-1] = 0;
+
+  msg = mutt_new_header ();
+  msg->env = mutt_new_envelope ();
+  msg->env->to = dnt; /* Note that this is not a copy! */
+  msg->env->subject = safe_strdup ("Disposition notification");
+
+  t = mutt_new_body ();
+  msg->content = t;
+  t->type = TYPEMULTIPART;
+  t->subtype = safe_strdup ("report");
+  t->encoding = ENC7BIT;
+  t->use_disp = 0;
+  t->disposition = DISPINLINE;
+  mutt_generate_boundary (&t->parameter);
+  mutt_set_parameter ("report-type", "disposition-notification",
+                      &t->parameter);
+
+  t->parts = mutt_new_body ();
+  t = t->parts;
+  t->type = TYPETEXT;
+  t->subtype = safe_strdup ("plain");
+  t->use_disp = 0;
+  t->disposition = DISPINLINE;
+  t->encoding = ENC7BIT;
+  mutt_mktemp (fnamebuf);
+  t->filename = safe_strdup (fnamebuf);
+  t->unlink = 1; 
+  if (!(fp = safe_fopen (t->filename, "w")))
+  {
+    mutt_perror (t->filename);
+    /* fixme: cleanup */
+    return;
+  }
+  fprintf (fp, "Original message info:\n\n");
+  if (cur->env->date)
+    fprintf (fp,       "    Date: %s\n", cur->env->date);
+  if (cur->env->to)
+    write_address (fp, "      To", "", cur->env->to, 0);
+  if (cur->env->subject)
+    fprintf (fp,       " Subject: %s\n", cur->env->subject);
+  fprintf (fp, "\n"
+    "The message has been displayed at %s.\n"
+    "This is no guarantee that the message has been read or understood.\n\n",
+     current_date);
+  fclose (fp);
+
+
+  t->next = mutt_new_body ();
+  t = t->next;
+  t->type = TYPEMESSAGE;
+  t->subtype = safe_strdup ("disposition-notification");
+  t->use_disp = 0;
+  t->disposition = DISPINLINE;
+  t->encoding = ENC7BIT;
+  mutt_mktemp (fnamebuf);
+  t->filename = safe_strdup (fnamebuf);
+  t->unlink = 1; 
+  if (!(fp = safe_fopen (t->filename, "w")))
+  {
+    mutt_perror (t->filename);
+    /* fixme: cleanup */
+    return;
+  }
+
+  fprintf (fp, "Reporting-UA: %s; Mutt/%s\n", Fqdn, MUTT_VERSION);
+  /*fprintf (fp, "Original-Recipient: rfc822;%s\n");*/
+
+
+  addr = NULL;
+  {
+    LIST *uh = UserHeader;
+
+    for (; uh; uh = uh->next)
+    {
+      if (!ascii_strncasecmp ("from:", uh->data, 5))
+      { /* User has specified a default From: address.  This has priority. */
+        addr = rfc822_parse_adrlist (addr, uh->data + 5);
+        break;
+      }
+    }
+  }
+  if (!addr)
+    addr = mutt_default_from ();
+
+  write_address (fp, "Final-Recipient", "rfc822;", addr, 1);
+  rfc822_free_address (&msg->env->from);
+  msg->env->from = addr;
+
+  if (cur->env->message_id)
+    fprintf (fp, "Original-Message-ID: %s\n", cur->env->message_id);
+
+  fprintf (fp, "Disposition: manual-action/MDN-sent-%s; displayed\n",
+           confirmed? "manually":"automatically");
+  fclose (fp);
+
+  if (!mutt_send_message_direct (msg, 1))
+    mutt_message (_("Message Disposition Notification sent."));
+
+  msg->env->to = NULL; /* we didn't used a copy */
+  mutt_free_envelope (&msg->env); msg->env = NULL;
+
+  mark_mdn_done (cur);
+}
+
+
+/* Have a look at the current message and decide whether a MDN should
+   be sent.  Return true if the user selected to ignore it for now. */
+int mutt_handle_mdn (HEADER *cur)
+{
+  int must_ask = 0;
+  int ask_this = 0;
+  int unknown_required = 0;
+  int confirmed = 0;
+  PARAMETER *parm;
+  ADDRESS *dnt_addr = NULL;
+  ADDRESS *a;
+
+  if (!option (OPTMDNENABLE) )
+    return 0; /* MDN support not enabled */
+
+  /* Do we have a notification header? */
+  if (!cur->env || !cur->env->dnt)
+    return 0; /* Nothing to do. */
+  if (cur->mdnsent)
+    return 0; /* Already sent. */
+
+  /* Check whether one of the notification addresses is in the deny
+     list. Add all non-denied addresses to a new list. */
+  for (a = cur->env->dnt; a; a = a->next)
+  {
+    if (!is_in_mdn_list (a, MdnDeny))
+    {
+      ADDRESS *aa = rfc822_cpy_adr_real (a);
+      rfc822_append (&dnt_addr, aa);
+      rfc822_free_address (&aa);
+    }
+  }
+
+  if (!dnt_addr)
+    {
+      mark_mdn_done (cur);
+      return 0; /* All addresses are in the deny list. */
+    }
+
+  /* Check whether we can handle all required options.  RFC2298 does
+     not define any yet, but we must be prepared for future extensions
+     and X-foo attributes. */
+  for (parm=cur->env->dno; parm; parm = parm->next)
+  {
+    if (!ascii_strcasecmp (parm->value, "required"))
+      unknown_required = 1;
+    else if (ascii_strcasecmp (parm->value, "optional"))
+      must_ask = 1; /* invalid importance value */
+  }
+  
+  if (unknown_required)
+  {
+    /* We don't sent a failed messages at all. */
+    mark_mdn_done (cur);
+    mutt_message (_("Required Disposition Notification Option unknown "
+                    "- DNT ignored"));
+    rfc822_free_address (&dnt_addr);
+    return 0;
+  }
+
+
+  /* Check that the Return-Path matches the DNT, a Return-Path exists
+     and that it does not comtain more than one address.*/
+  if (dnt_addr->next)
+    must_ask = 1; /* More than one address. */
+  else if (!cur->env->return_path)
+    must_ask = 1;
+  else if (cur->env->return_path->next)
+    must_ask = 1;
+  else if (address_compare (dnt_addr, cur->env->return_path))
+    must_ask = 1; /* Addresses don't match. */
+  else if ( option (OPTMDNCONFIRM) )
+    ask_this = 1;
+
+  /* Check the allow list, which overrides the above. */
+  if (must_ask || ask_this)
+  {
+    for (a = dnt_addr; a; a = a->next)
+      if (!is_in_mdn_list (a, MdnAllow))
+        break;
+    if (!a) /* All addresses are in the allow list. */
+      must_ask = ask_this = 0;
+  }
+
+ 
+  /* Get confirmation if required. */
+  if (must_ask)
+  {
+    switch (mutt_yesorno (_("Disposition-Notification request is questionable."
+                            "  Really send?"), M_NO))
+    {
+      case M_YES:
+       break;
+      case M_NO:
+        mark_mdn_done (cur);
+        rfc822_free_address (&dnt_addr);
+        return 0;
+      default:
+        /* ^G */ 
+        rfc822_free_address (&dnt_addr);
+        return 1; /* ignore/postponed */
+    }
+    confirmed = 1;
+  }
+  else if (ask_this)
+  {
+    switch (mutt_yesorno (_("Disposition-Notification requested.  "
+                            "Send?"), M_YES))
+    {
+      case M_YES:
+       break;
+      case M_NO:
+        mark_mdn_done (cur);
+        rfc822_free_address (&dnt_addr);
+        return 0;
+      default:
+        /* ^G */ 
+        rfc822_free_address (&dnt_addr);
+        return 1; /* ignore/postponed */
+    }
+    confirmed = 1;
+  }
+
+  mutt_send_mdn (cur, confirmed, dnt_addr);
+  rfc822_free_address (&dnt_addr);
+  return 0;
+}
+
 int mutt_display_message (HEADER *cur)
 {
   char tempfile[_POSIX_PATH_MAX], buf[LONG_STRING];
@@ -153,6 +459,8 @@ int mutt_display_message (HEADER *cur)
     mutt_unlink (tempfile);
     return 0;
   }
+
+  mutt_handle_mdn (cur);
 
   if (fpfilterout != NULL && mutt_wait_filter (filterpid) != 0)
     mutt_any_key_to_continue (NULL);
diff -r f467353f5657 compose.c
--- a/compose.c Sat Mar 31 18:50:39 2007 -0700
+++ b/compose.c Fri Oct 12 11:41:36 2007 -0500
@@ -59,6 +59,7 @@ enum
   HDR_SUBJECT,
   HDR_REPLYTO,
   HDR_FCC,
+  HDR_DNT,                     /* Disposition-Notification-To  */
 
 #ifdef MIXMASTER
   HDR_MIX,
@@ -67,7 +68,7 @@ enum
   HDR_CRYPT,
   HDR_CRYPTINFO,
 
-  HDR_ATTACH  = (HDR_FCC + 5) /* where to start printing the attachments */
+  HDR_ATTACH  = (HDR_DNT + 5) /* where to start printing the attachments */
 };
 
 #define HDR_XOFFSET 10
@@ -82,7 +83,8 @@ static char *Prompts[] =
   "Bcc: ",
   "Subject: ",
   "Reply-To: ",
-  "Fcc: "
+  "Fcc: ",
+  "Dnt: "
 };
 
 static struct mapping_t ComposeHelp[] = {
@@ -260,6 +262,8 @@ static void draw_envelope (HEADER *msg, 
   draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to);
   mvprintw (HDR_FCC, 0, TITLE_FMT, Prompts[HDR_FCC - 1]);
   mutt_paddstr (W, fcc);
+  if (option(OPTMDNENABLE))
+    draw_envelope_addr (HDR_DNT, msg->env->dnt);
 
   if (WithCrypto)
     redraw_crypt_lines (msg);
@@ -310,6 +314,47 @@ static int edit_address_list (int line, 
   move (line, HDR_XOFFSET);
   mutt_paddstr (W, buf);
   
+  return 0;
+}
+
+static int switch_to_next_dnt (int line, ADDRESS **addr, int *current_dnt)
+{
+  char buf[HUGE_STRING] = ""; /* needs to be large for alias expansion */
+  LIST *p;
+  int i, idx = *current_dnt + 1;
+
+  if (!MdnDntDefaults)
+    return 0;
+  
+  rfc822_free_address (addr);
+  p = MdnDntDefaults;
+  for (i = 0; i < idx; i++)
+  {
+    p = p->next;
+    if (!p)
+      break;
+  }
+  if (!p)
+    idx = -1;
+  *current_dnt = idx;
+
+  if (!p || !p->data || !strcmp (p->data, "none") )
+    *addr = mutt_parse_adrlist (*addr, "");
+  else
+    *addr = mutt_parse_adrlist (*addr, p->data);
+
+  if (option (OPTNEEDREDRAW))
+  {
+    unset_option (OPTNEEDREDRAW);
+    return (REDRAW_FULL);
+  }
+
+  /* redraw the expanded list so the user can see the result */
+  buf[0] = 0;
+  rfc822_write_address (buf, sizeof (buf), *addr, 1);
+  move (line, HDR_XOFFSET);
+  mutt_paddstr (W, buf);
+
   return 0;
 }
 
@@ -507,6 +552,7 @@ int mutt_compose_menu (HEADER *msg,   /*
   /* Sort, SortAux could be changed in mutt_index_menu() */
   int oldSort, oldSortAux;
   struct stat st;
+  int current_dnt = -1;
 
   mutt_attach_init (msg->content);
   idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
@@ -520,6 +566,20 @@ int mutt_compose_menu (HEADER *msg,   /*
   menu->data = idx;
   menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, 
ComposeHelp);
   
+  if ( option(OPTMDNENABLE) && MdnDntDefaults && MdnDntDefaults->data
+       && !(msg->env->dnt && msg->env->dnt->mailbox
+            && *msg->env->dnt->mailbox))
+  {
+    rfc822_free_address (&msg->env->dnt);
+    if (!MdnDntDefaults || !MdnDntDefaults->data
+        || !strcmp (MdnDntDefaults->data, "none") )
+      msg->env->dnt = mutt_parse_adrlist (msg->env->dnt, "");
+    else
+      msg->env->dnt = mutt_parse_adrlist (msg->env->dnt,
+                                          MdnDntDefaults->data);
+    current_dnt++;
+  }
+  
   while (loop)
   {
     switch (op = mutt_menuLoop (menu))
@@ -576,6 +636,15 @@ int mutt_compose_menu (HEADER *msg,   /*
        }
        MAYBE_REDRAW (menu->redraw);
         mutt_message_hook (NULL, msg, M_SEND2HOOK);
+        break;
+      case OP_COMPOSE_EDIT_DNT:
+        if (option (OPTMDNENABLE))
+          menu->redraw = edit_address_list (HDR_DNT, &msg->env->dnt);
+      break;
+      case OP_COMPOSE_SWITCH_DNT:
+        if (option (OPTMDNENABLE))
+          menu->redraw = switch_to_next_dnt (HDR_DNT, &msg->env->dnt,
+                                             &current_dnt);
         break;
       case OP_COMPOSE_EDIT_MESSAGE:
        if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option 
(OPTEDITHDRS))
diff -r f467353f5657 copy.c
--- a/copy.c    Sat Mar 31 18:50:39 2007 -0700
+++ b/copy.c    Fri Oct 12 11:41:36 2007 -0500
@@ -433,7 +433,7 @@ mutt_copy_header (FILE *in, HEADER *h, F
          return (-1);
       }
 
-      if (h->flagged || h->replied)
+      if (h->flagged || h->replied | h->mdnsent)
       {
        if (fputs ("X-Status: ", out) == EOF)
          return (-1);
@@ -447,6 +447,12 @@ mutt_copy_header (FILE *in, HEADER *h, F
        if (h->flagged)
        {
          if (fputc ('F', out) == EOF)
+           return (-1);
+       }
+       
+       if (h->mdnsent)
+       {
+         if (fputc ('N', out) == EOF)
            return (-1);
        }
        
diff -r f467353f5657 flags.c
--- a/flags.c   Sat Mar 31 18:50:39 2007 -0700
+++ b/flags.c   Fri Oct 12 11:41:36 2007 -0500
@@ -202,6 +202,24 @@ void _mutt_set_flag (CONTEXT *ctx, HEADE
       }
       break;
 
+    case M_MDNSENT:
+      if (bf)
+      {
+       if (!h->mdnsent)
+       {
+         h->mdnsent = bf;
+         h->changed = 1;
+         if (upd_ctx) ctx->changed = 1;
+       }
+      }
+      else if (h->mdnsent)
+      {
+       h->mdnsent = 0;
+       h->changed = 1;
+        if (upd_ctx) ctx->changed = 1;
+      }
+      break;
+
     case M_FLAG:
 
       if (!mutt_bit_isset(ctx->rights,M_ACL_WRITE))
diff -r f467353f5657 functions.h
--- a/functions.h       Sat Mar 31 18:50:39 2007 -0700
+++ b/functions.h       Fri Oct 12 11:41:36 2007 -0500
@@ -314,6 +314,8 @@ struct binding_t OpCompose[] = { /* map:
   { "print-entry",     OP_PRINT,                       "l" },
   { "edit-mime",       OP_COMPOSE_EDIT_MIME,           "m" },
   { "new-mime",                OP_COMPOSE_NEW_MIME,            "n" },
+  { "edit-dnt",         OP_COMPOSE_EDIT_DNT,            "\033n" },
+  { "switch-dnt",       OP_COMPOSE_SWITCH_DNT,          "\033N" },
   { "postpone-message",        OP_COMPOSE_POSTPONE_MESSAGE,    "P" },
   { "edit-reply-to",   OP_COMPOSE_EDIT_REPLY_TO,       "r" },
   { "rename-file",     OP_COMPOSE_RENAME_FILE,         "R" },
diff -r f467353f5657 globals.h
--- a/globals.h Sat Mar 31 18:50:39 2007 -0700
+++ b/globals.h Fri Oct 12 11:41:36 2007 -0500
@@ -83,6 +83,7 @@ WHERE char *MhReplied;
 WHERE char *MhReplied;
 WHERE char *MhUnseen;
 WHERE char *MsgFmt;
+WHERE char *MhMdnsent;
 
 #ifdef USE_SOCKET
 WHERE char *Preconnect INITVAL (NULL);
@@ -163,6 +164,9 @@ WHERE LIST *Ignore INITVAL(0);
 WHERE LIST *Ignore INITVAL(0);
 WHERE LIST *MimeLookupList INITVAL(0);
 WHERE LIST *UnIgnore INITVAL(0);
+WHERE LIST *MdnAllow INITVAL(0);
+WHERE LIST *MdnDeny  INITVAL(0);
+WHERE LIST *MdnDntDefaults INITVAL(0);
 
 WHERE RX_LIST *Alternates INITVAL(0);
 WHERE RX_LIST *UnAlternates INITVAL(0);
diff -r f467353f5657 handler.c
--- a/handler.c Sat Mar 31 18:50:39 2007 -0700
+++ b/handler.c Fri Oct 12 11:41:36 2007 -0500
@@ -1527,6 +1527,8 @@ int mutt_body_handler (BODY *b, STATE *s
       plaintext = 1;
     else if (!ascii_strcasecmp ("external-body", b->subtype))
       handler = external_body_handler;
+    else if (!ascii_strcasecmp ("disposition-notification", b->subtype))
+      plaintext = 1;
   }
   else if (b->type == TYPEMULTIPART)
   {
diff -r f467353f5657 init.c
--- a/init.c    Sat Mar 31 18:50:39 2007 -0700
+++ b/init.c    Fri Oct 12 11:41:36 2007 -0500
@@ -1494,6 +1494,31 @@ parse_sort (short *val, const char *s, c
   return 0;
 }
 
+/* FIXME? */
+static int parse_mdn_allow_deny (BUFFER *buf, BUFFER *s,
+                                 unsigned long data, BUFFER *err)
+{
+  do
+  {
+    mutt_extract_token (buf, s, 0);
+    add_to_list ((LIST **) data, buf->data);
+  }
+  while (MoreArgs (s));
+
+  return 0;
+}
+
+static int parse_mdn_dnt_defaults (BUFFER *buf, BUFFER *s,
+                                   unsigned long data, BUFFER *err)
+{
+
+  mutt_extract_token (buf, s, M_TOKEN_SPACE | M_TOKEN_QUOTE);
+  add_to_list ((LIST **) data, buf->data);
+  memset (buf, 0, sizeof (BUFFER));
+
+  return 0;
+}
+
 static void mutt_set_default (struct option_t *p)
 {
   switch (p->type & DT_MASK)
diff -r f467353f5657 init.h
--- a/init.h    Sat Mar 31 18:50:39 2007 -0700
+++ b/init.h    Fri Oct 12 11:41:36 2007 -0500
@@ -1206,6 +1206,21 @@ struct option_t MuttVars[] = {
   ** high bit from ``0xf8'' is ``0x78'', which is the ASCII character
   ** ``x''.
   */
+  { "mdn_enable",      DT_BOOL, R_NONE, OPTMDNENABLE, 0 },
+  /*
+  ** .pp
+  ** When set, the message disposition notification support (RFC-2298)
+  ** is enabled.  This shows an extra menu entry in the composer menu and
+  ** enables all the other MDN features.  Keep it disabled to prevent any
+  ** disposition notifications to be send.
+  */
+  { "mdn_confirm",     DT_BOOL, R_NONE, OPTMDNCONFIRM, 0 },
+  /*
+  ** .pp
+  ** When set, a confirmation to send a message disposition
+  ** notification is always requested.  When unset, a confirmation is
+  ** only requested for suspect messages as demanded by RFC-2298.
+  */
   { "mh_purge",                DT_BOOL, R_NONE, OPTMHPURGE, 0 },
   /*
   ** .pp
@@ -1223,6 +1238,12 @@ struct option_t MuttVars[] = {
   /*
   ** .pp
   ** The name of the MH sequence used to tag replied messages.
+  */
+  { "mh_seq_mdnsent",  DT_STR, R_NONE, UL &MhMdnsent, UL "mdnsent" },
+  /*
+  ** .pp
+  ** The name of the MH sequence used to mark messages for whom a 
+  ** message disposition notice has already been sent.
   */
   { "mh_seq_unseen",   DT_STR, R_NONE, UL &MhUnseen, UL "unseen" },
   /*
@@ -3080,6 +3101,8 @@ static int parse_unsubscribe (BUFFER *, 
 static int parse_unsubscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 static int parse_attachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
 static int parse_unattachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_mdn_allow_deny (BUFFER *buf, BUFFER *s, unsigned long data, 
BUFFER *err);
+static int parse_mdn_dnt_defaults (BUFFER *buf, BUFFER *s, unsigned long data, 
BUFFER *err);
 
 
 static int parse_alternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
@@ -3129,6 +3152,9 @@ struct command_t Commands[] = {
   { "macro",           mutt_parse_macro,       0 },
   { "mailboxes",       mutt_parse_mailboxes,   M_MAILBOXES },
   { "unmailboxes",     mutt_parse_mailboxes,   M_UNMAILBOXES },
+  { "mdn_allow",        parse_mdn_allow_deny,   UL &MdnAllow },
+  { "mdn_deny",         parse_mdn_allow_deny,   UL &MdnDeny },
+  { "mdn_dnt_defaults", parse_mdn_dnt_defaults, UL &MdnDntDefaults },
   { "message-hook",    mutt_parse_hook,        M_MESSAGEHOOK },
   { "mbox-hook",       mutt_parse_hook,        M_MBOXHOOK },
   { "mime_lookup",     parse_list,     UL &MimeLookupList },
diff -r f467353f5657 mbox.c
--- a/mbox.c    Sat Mar 31 18:50:39 2007 -0700
+++ b/mbox.c    Fri Oct 12 11:41:36 2007 -0500
@@ -1181,6 +1181,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, i
          mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied);
          mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old);
          mutt_set_flag (ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read);
+         mutt_set_flag (ctx, ctx->hdrs[i], M_MDNSENT, old_hdrs[j]->mdnsent);
        }
        mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted);
        mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged);
diff -r f467353f5657 mh.c
--- a/mh.c      Sat Mar 31 18:50:39 2007 -0700
+++ b/mh.c      Fri Oct 12 11:41:37 2007 -0500
@@ -84,6 +84,7 @@ struct mh_data
 #define MH_SEQ_UNSEEN  (1 << 0)
 #define MH_SEQ_REPLIED (1 << 1)
 #define MH_SEQ_FLAGGED (1 << 2)
+#define MH_SEQ_MDNSENT (1 << 3)
 
 static inline struct mh_data *mh_data (CONTEXT *ctx)
 {
@@ -325,10 +326,12 @@ void mh_update_sequences (CONTEXT * ctx)
   int unseen = 0;
   int flagged = 0;
   int replied = 0;
+  int mdnsent = 0;
 
   char seq_unseen[STRING];
   char seq_replied[STRING];
   char seq_flagged[STRING];
+  char seq_mdnsent[STRING];
 
 
   struct mh_sequences mhs;
@@ -337,6 +340,7 @@ void mh_update_sequences (CONTEXT * ctx)
   snprintf (seq_unseen, sizeof (seq_unseen), "%s:", NONULL (MhUnseen));
   snprintf (seq_replied, sizeof (seq_replied), "%s:", NONULL (MhReplied));
   snprintf (seq_flagged, sizeof (seq_flagged), "%s:", NONULL (MhFlagged));
+  snprintf (seq_mdnsent, sizeof (seq_mdnsent), "%s:", NONULL (MhMdnsent));
 
   if (mh_mkstemp (ctx, &nfp, &tmpfname) != 0)
   {
@@ -358,13 +362,15 @@ void mh_update_sequences (CONTEXT * ctx)
        continue;
       if (!mutt_strncmp (buff, seq_replied, mutt_strlen (seq_replied)))
        continue;
+      if (!mutt_strncmp (buff, seq_mdnsent, mutt_strlen (seq_mdnsent)))
+       continue;
 
       fprintf (nfp, "%s\n", buff);
     }
   }
   safe_fclose (&ofp);
 
-  /* now, update our unseen, flagged, and replied sequences */
+  /* now, update our unseen, flagged, replied and mdnsent sequences */
   for (l = 0; l < ctx->msgcount; l++)
   {
     if (ctx->hdrs[l]->deleted)
@@ -391,6 +397,11 @@ void mh_update_sequences (CONTEXT * ctx)
     {
       mhs_set (&mhs, i, MH_SEQ_REPLIED);
       replied++;
+    }
+    if (ctx->hdrs[l]->mdnsent)
+    {
+      mhs_set (&mhs, i, MH_SEQ_MDNSENT);
+      mdnsent++;
     }
   }
 
@@ -401,6 +412,8 @@ void mh_update_sequences (CONTEXT * ctx)
     mhs_write_one_sequence (nfp, &mhs, MH_SEQ_FLAGGED, NONULL (MhFlagged));
   if (replied)
     mhs_write_one_sequence (nfp, &mhs, MH_SEQ_REPLIED, NONULL (MhReplied));
+  if (mdnsent)
+    mhs_write_one_sequence (nfp, &mhs, MH_SEQ_MDNSENT, NONULL (MhMdnsent));
 
   mhs_free_sequences (&mhs);
 
@@ -509,6 +522,7 @@ static void mh_update_maildir (struct ma
     md->h->read = (f & MH_SEQ_UNSEEN) ? 0 : 1;
     md->h->flagged = (f & MH_SEQ_FLAGGED) ? 1 : 0;
     md->h->replied = (f & MH_SEQ_REPLIED) ? 1 : 0;
+    md->h->mdnsent = (f & MH_SEQ_MDNSENT) ? 1 : 0;
   }
 }
 
@@ -547,6 +561,7 @@ static void maildir_parse_flags (HEADER 
   h->flagged = 0;
   h->read = 0;
   h->replied = 0;
+  h->mdnsent = 0;
 
   if ((p = strrchr (path, ':')) != NULL && mutt_strncmp (p + 1, "2,", 2) == 0)
   {
@@ -579,6 +594,10 @@ static void maildir_parse_flags (HEADER 
        h->deleted = 1;
        break;
       
+      case 'N':                /* MDN has already been sent */
+       h->mdnsent = 1;
+       break;
+
       default:
        *q++ = *p;
        break;
@@ -837,10 +856,11 @@ static int maildir_add_to_context (CONTE
     {
       dprint (2,
              (debugfile,
-              "%s:%d Adding header structure. Flags: %s%s%s%s%s\n", __FILE__,
+              "%s:%d Adding header structure. Flags: %s%s%s%s%s%s\n", __FILE__,
               __LINE__, md->h->flagged ? "f" : "", md->h->deleted ? "D" : "",
               md->h->replied ? "r" : "", md->h->old ? "O" : "",
-              md->h->read ? "R" : ""));
+              md->h->read ? "R" : "",
+              md->h->mdnsent ? "N" : ""));
       if (ctx->msgcount == ctx->hdrmax)
        mx_alloc_memory (ctx);
 
@@ -1145,10 +1165,12 @@ static void maildir_flags (char *dest, s
   {
     char tmp[LONG_STRING];
     snprintf (tmp, sizeof (tmp),
-             "%s%s%s%s%s",
+             "%s%s%s%s%s%s",
              hdr->flagged ? "F" : "",
              hdr->replied ? "R" : "",
-             hdr->read ? "S" : "", hdr->deleted ? "T" : "",
+             hdr->read ? "S" : "",
+             hdr->deleted ? "T" : "",
+             hdr->mdnsent ? "N" : "",
              NONULL(hdr->maildir_flags));
     if (hdr->maildir_flags)
       qsort (tmp, strlen (tmp), 1, ch_compar);
@@ -1725,6 +1747,7 @@ static void maildir_update_flags (CONTEX
    */
   mutt_set_flag (ctx, o, M_FLAG, n->flagged);
   mutt_set_flag (ctx, o, M_REPLIED, n->replied);
+  mutt_set_flag (ctx, o, M_MDNSENT, n->mdnsent);
   mutt_set_flag (ctx, o, M_READ, n->read);
   mutt_set_flag (ctx, o, M_OLD, n->old);
 
diff -r f467353f5657 mutt.h
--- a/mutt.h    Sat Mar 31 18:50:39 2007 -0700
+++ b/mutt.h    Fri Oct 12 11:41:37 2007 -0500
@@ -207,6 +207,7 @@ enum
   M_LIMIT,
   M_EXPIRED,
   M_SUPERSEDED,
+  M_MDNSENT,
 
   /* actions for mutt_pattern_comp/mutt_pattern_exec */
   M_AND,
@@ -402,6 +403,8 @@ enum
   OPTMENUMOVEOFF,      /* allow menu to scroll past last entry */
   OPTMETAKEY,          /* interpret ALT-x as ESC-x */
   OPTMETOO,
+  OPTMDNENABLE,         /* enable the MDN support */
+  OPTMDNCONFIRM,        /* always require confirmation before sending an MDN */
   OPTMHPURGE,
   OPTMIMEFORWDECODE,
   OPTNARROWTREE,
@@ -575,6 +578,13 @@ typedef struct alias
   short num;
 } ALIAS;
 
+typedef struct parameter
+{
+  char *attribute;
+  char *value;
+  struct parameter *next;
+} PARAMETER;
+
 typedef struct envelope
 {
   ADDRESS *return_path;
@@ -585,6 +595,8 @@ typedef struct envelope
   ADDRESS *sender;
   ADDRESS *reply_to;
   ADDRESS *mail_followup_to;
+  ADDRESS *dnt;                 /* disposition-notification-to */
+  PARAMETER *dno;               /* disposition-notification-options */
   char *list_post;             /* this stores a mailto URL, or nothing */
   char *subject;
   char *real_subj;             /* offset of the real subject */
@@ -600,13 +612,6 @@ typedef struct envelope
   unsigned int irt_changed : 1; /* In-Reply-To changed to link/break threads */
   unsigned int refs_changed : 1; /* References changed to break thread */
 } ENVELOPE;
-
-typedef struct parameter
-{
-  char *attribute;
-  char *value;
-  struct parameter *next;
-} PARAMETER;
 
 /* Information that helps in determing the Content-* of an attachment */
 typedef struct content
@@ -716,6 +721,7 @@ typedef struct header
   unsigned int expired : 1;            /* already expired? */
   unsigned int superseded : 1;                 /* got superseded? */
   unsigned int replied : 1;
+  unsigned int mdnsent : 1;             /* track whether an MDN has been sent*/
   unsigned int subject_changed : 1;    /* used for threading */
   unsigned int threaded : 1;           /* used for threading */
   unsigned int display_subject : 1;    /* used for threading */
diff -r f467353f5657 muttlib.c
--- a/muttlib.c Sat Mar 31 18:50:39 2007 -0700
+++ b/muttlib.c Fri Oct 12 11:41:37 2007 -0500
@@ -665,6 +665,9 @@ void mutt_free_envelope (ENVELOPE **p)
   rfc822_free_address (&(*p)->bcc);
   rfc822_free_address (&(*p)->sender);
   rfc822_free_address (&(*p)->reply_to);
+  rfc822_free_address (&(*p)->dnt);
+  if ((*p)->dno)
+    mutt_free_parameter (&(*p)->dno);
   rfc822_free_address (&(*p)->mail_followup_to);
 
   FREE (&(*p)->list_post);
diff -r f467353f5657 parse.c
--- a/parse.c   Sat Mar 31 18:50:39 2007 -0700
+++ b/parse.c   Fri Oct 12 11:41:37 2007 -0500
@@ -1054,6 +1054,25 @@ int mutt_parse_rfc822_line (ENVELOPE *e,
        hdr->date_sent = mutt_parse_date (p, hdr);
       matched = 1;
     }
+    else if (!ascii_strcasecmp (line + 1, "isposition-notification-to"))
+      {
+       e->dnt = rfc822_parse_adrlist (e->dnt, p);
+       matched = 1;
+      }
+    else if (!ascii_strcasecmp (line + 1, "isposition-notification-options"))
+      {
+       if (!e->dno)
+         e->dno = parse_parameters (p);
+       else
+         {
+           PARAMETER *tmp;
+        
+           for (tmp=e->dno; tmp->next; tmp = tmp->next)
+             ;
+           tmp->next = parse_parameters (p);
+         }
+       matched = 1;
+      }
     break;
     
     case 'e':
@@ -1247,6 +1266,9 @@ int mutt_parse_rfc822_line (ENVELOPE *e,
            case 'F':
            hdr->flagged = 1;
            break;
+            case 'N':
+            hdr->mdnsent = 1;
+            break;
            default:
            break;
          }
@@ -1432,6 +1454,7 @@ ENVELOPE *mutt_read_rfc822_header (FILE 
     rfc2047_decode_adrlist (e->cc);
     rfc2047_decode_adrlist (e->bcc);
     rfc2047_decode_adrlist (e->reply_to);
+    rfc2047_decode_adrlist (e->dnt);
     rfc2047_decode_adrlist (e->mail_followup_to);
     rfc2047_decode_adrlist (e->return_path);
     rfc2047_decode_adrlist (e->sender);
diff -r f467353f5657 protos.h
--- a/protos.h  Sat Mar 31 18:50:39 2007 -0700
+++ b/protos.h  Fri Oct 12 11:41:37 2007 -0500
@@ -299,7 +299,8 @@ int mutt_group_match (group_t *g, const 
 int mutt_group_match (group_t *g, const char *s);
 int mutt_group_context_add_rx (group_context_t *ctx, const char *s, int flags, 
BUFFER *err);
 int mutt_index_menu (void);
-int mutt_invoke_sendmail (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const 
char *, int);
+int mutt_send_message_direct (HEADER *msg, int nullrp);
+int mutt_invoke_sendmail (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const 
char *, int, int);
 int mutt_is_autoview (BODY *, const char *);
 int mutt_is_mail_list (ADDRESS *);
 int mutt_is_message_type(int, const char *);
@@ -343,7 +344,7 @@ int mutt_search_command (int, int);
 int mutt_search_command (int, int);
 #ifdef USE_SMTP
 int mutt_smtp_send (const ADDRESS *, const ADDRESS *, const ADDRESS *,
-                    const ADDRESS *, const char *, int);
+                    const ADDRESS *, const char *, int, int);
 #endif
 int mutt_strwidth (const char *);
 int mutt_compose_menu (HEADER *, char *, size_t, HEADER *);
diff -r f467353f5657 send.c
--- a/send.c    Sat Mar 31 18:50:39 2007 -0700
+++ b/send.c    Fri Oct 12 11:41:37 2007 -0500
@@ -302,7 +302,9 @@ static void process_user_header (ENVELOP
     else if (ascii_strncasecmp ("to:", uh->data, 3) != 0 &&
             ascii_strncasecmp ("cc:", uh->data, 3) != 0 &&
             ascii_strncasecmp ("bcc:", uh->data, 4) != 0 &&
-            ascii_strncasecmp ("subject:", uh->data, 8) != 0)
+            ascii_strncasecmp ("subject:", uh->data, 8) != 0 &&
+            !(ascii_strncasecmp ("disposition-notification-to:",
+                                  uh->data, 28) == 0 && env->dnt))
     {
       if (last)
       {
@@ -956,7 +958,7 @@ ADDRESS *mutt_default_from (void)
   return (adr);
 }
 
-static int send_message (HEADER *msg)
+static int send_message (HEADER *msg, int nullrp)
 {  
   char tempfile[_POSIX_PATH_MAX];
   FILE *tempfp;
@@ -1011,13 +1013,20 @@ static int send_message (HEADER *msg)
   if (SmtpUrl)
       return mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc,
                              msg->env->bcc, tempfile,
-                             (msg->content->encoding == ENC8BIT));
+                             (msg->content->encoding == ENC8BIT), nullrp);
 #endif /* USE_SMTP */
 
   i = mutt_invoke_sendmail (msg->env->from, msg->env->to, msg->env->cc, 
-                           msg->env->bcc, tempfile,
-                            (msg->content->encoding == ENC8BIT));
+                            msg->env->bcc, tempfile,
+                            (msg->content->encoding == ENC8BIT), nullrp);
   return (i);
+}
+
+/* Send a message as defined by MSG without any user interaction.  If
+   NULLRP is set to true, a NULL return path (<>) will be used. */
+int mutt_send_message_direct (HEADER *msg, int nullrp)
+{
+  return send_message (msg, nullrp);
 }
 
 /* rfc2047 encode the content-descriptions */
@@ -1733,7 +1742,7 @@ full_fcc:
    * the send failed as well so we give the user a chance to fix the
    * error.
    */
-  if (fcc_error || (i = send_message (msg)) == -1)
+  if (fcc_error || (i = send_message (msg, 0)) == -1)
   {
     if (!(flags & SENDBATCH))
     {
diff -r f467353f5657 sendlib.c
--- a/sendlib.c Sat Mar 31 18:50:39 2007 -0700
+++ b/sendlib.c Fri Oct 12 11:41:37 2007 -0500
@@ -1781,6 +1781,12 @@ int mutt_write_rfc822_header (FILE *fp, 
     mutt_write_address_list (env->mail_followup_to, fp, 18, 0);
   }
 
+  if (env->dnt && !privacy)
+  {
+    fputs ("Disposition-Notification-To: ", fp);
+    mutt_write_address_list (env->dnt, fp, 29, 0);
+  }
+
   if (mode <= 0)
   {
     if (env->references)
@@ -2112,7 +2118,8 @@ mutt_invoke_sendmail (ADDRESS *from,      /* 
 mutt_invoke_sendmail (ADDRESS *from,   /* the sender */
                 ADDRESS *to, ADDRESS *cc, ADDRESS *bcc, /* recips */
                 const char *msg, /* file containing message */
-                int eightbit) /* message contains 8bit chars */
+                int eightbit, /* message contains 8bit chars */
+                int nullrp)
 {
   char *ps = NULL, *path = NULL, *s = safe_strdup (Sendmail), *childout = NULL;
   char **args = NULL;
@@ -2145,7 +2152,13 @@ mutt_invoke_sendmail (ADDRESS *from,     /* 
   if (eightbit && option (OPTUSE8BITMIME))
     args = add_option (args, &argslen, &argsmax, "-B8BITMIME");
 
-  if (option (OPTENVFROM))
+  if (nullrp)
+  {
+    args = add_option (args, &argslen, &argsmax, "-f");
+    args = add_option (args, &argslen, &argsmax, "<>");
+  }
+
+  else if (option (OPTENVFROM))
   {
     if (EnvFrom)
     {
@@ -2303,6 +2316,7 @@ void mutt_prepare_envelope (ENVELOPE *en
   rfc2047_encode_adrlist (env->from, "From");
   rfc2047_encode_adrlist (env->mail_followup_to, "Mail-Followup-To");
   rfc2047_encode_adrlist (env->reply_to, "Reply-To");
+  rfc2047_encode_adrlist (env->dnt, "Disposition-Notification-To");
 
   if (env->subject)
   {
@@ -2326,6 +2340,7 @@ void mutt_unprepare_envelope (ENVELOPE *
   rfc2047_decode_adrlist (env->bcc);
   rfc2047_decode_adrlist (env->from);
   rfc2047_decode_adrlist (env->reply_to);
+  rfc2047_decode_adrlist (env->dnt);
   rfc2047_decode (&env->subject);
 }
 
@@ -2374,11 +2389,11 @@ static int _mutt_bounce_message (FILE *f
 #if USE_SMTP
     if (SmtpUrl)
       ret = mutt_smtp_send (env_from, to, NULL, NULL, tempfile,
-                            h->content->encoding == ENC8BIT);
+                            h->content->encoding == ENC8BIT, 0);
     else
 #endif /* USE_SMTP */
     ret = mutt_invoke_sendmail (env_from, to, NULL, NULL, tempfile,
-                               h->content->encoding == ENC8BIT);
+                               (h->content->encoding == ENC8BIT), 0);
   }
 
   if (msg)
diff -r f467353f5657 smtp.c
--- a/smtp.c    Sat Mar 31 18:50:39 2007 -0700
+++ b/smtp.c    Fri Oct 12 11:41:37 2007 -0500
@@ -206,7 +206,7 @@ smtp_data (CONNECTION * conn, const char
 
 int
 mutt_smtp_send (const ADDRESS* from, const ADDRESS* to, const ADDRESS* cc,
-                const ADDRESS* bcc, const char *msgfile, int eightbit)
+                const ADDRESS* bcc, const char *msgfile, int eightbit, int 
nullrp)
 {
   CONNECTION *conn;
   ACCOUNT account;
@@ -230,7 +230,7 @@ mutt_smtp_send (const ADDRESS* from, con
 
     /* send the sender's address */
     ret = snprintf (buf, sizeof (buf), "MAIL FROM:<%s>",
-                    EnvFrom ? EnvFrom->mailbox : from->mailbox);
+                    nullrp ? "" : EnvFrom ? EnvFrom->mailbox : from->mailbox);
     if (eightbit && mutt_bit_isset (Capabilities, EIGHTBITMIME))
     {
       safe_strncat (buf, sizeof (buf), " BODY=8BITMIME", 15);