Index: commands.c
===================================================================
--- commands.c	(revision a16d7e5b1281bf21e0fe52b6d9946fd58893da28)
+++ commands.c	(revision efeec7f945a0024cc21af30c2e6c2110bb5d3c6b)
@@ -693,4 +693,13 @@
 	      "current view.\n"),
   OWLCMD_ALIAS("del", "delete"),
+
+  OWLCMD_ARGS("delete-and-expunge", owl_command_delete_and_expunge, OWL_CTX_INTERACTIVE,
+              "delete a message",
+              "delete-and-expunge [-id msgid] [-q | --quiet]",
+              "If no message id is specified the current message is deleted.\n"
+              "Otherwise the message with the given message id is deleted.\n"
+              "If --quiet is specified, then there is no message displayed on\n"
+              "success.\n"),
+  OWLCMD_ALIAS("delx", "delete-and-expunge"),
 
   OWLCMD_ARGS("undelete", owl_command_undelete, OWL_CTX_INTERACTIVE,
@@ -2354,4 +2363,31 @@
 }
 
+char *owl_command_delete_and_expunge(int argc, const char *const *argv, const char *buff)
+{
+  bool exclaim_success = true;
+
+  if (argc > 1 && (!strcmp(argv[1], "-q") || !strcmp(argv[1], "--quiet"))) {
+    exclaim_success = false;
+    argc--;
+    argv++;
+  } else if (!strcmp(argv[argc - 1], "-q") || !strcmp(argv[argc - 1], "--quiet")) {
+    exclaim_success = false;
+    argc--;
+  }
+
+  if (argc == 1) {
+    owl_function_delete_and_expunge_cur(exclaim_success);
+    return NULL;
+  }
+
+  if (argc == 3 && (!strcmp(argv[1], "-id") || !strcmp(argv[1], "--id"))) {
+    owl_function_delete_and_expunge_by_id(atoi(argv[2]), exclaim_success);
+    return NULL;
+  }
+
+  owl_function_makemsg("Unknown arguments to delete-and-expunge command");
+  return NULL;
+}
+
 char *owl_command_undelete(int argc, const char *const *argv, const char *buff)
 {
Index: functions.c
===================================================================
--- functions.c	(revision 3eeb6ed02736fb9bb741381dae049c4692cb4027)
+++ functions.c	(revision efeec7f945a0024cc21af30c2e6c2110bb5d3c6b)
@@ -662,4 +662,34 @@
 }
 
+void owl_function_delete_and_expunge_message(int n)
+{
+  owl_messagelist *ml = owl_global_get_msglist(&g);
+  owl_view *v = owl_global_get_current_view(&g);
+  int lastmsgid = owl_function_get_curmsg_id(v);
+
+  /* delete and expunge the message */
+  owl_messagelist_delete_and_expunge_element(ml, n);
+
+  owl_function_redisplay_to_nearest(lastmsgid, v);
+}
+
+void owl_function_delete_and_expunge_cur(bool exclaim_success)
+{
+  int curmsg;
+  const owl_view *v = owl_global_get_current_view(&g);
+
+  /* bail if there's no current message */
+  if (owl_view_get_size(v) < 1) {
+    owl_function_error("No current message to delete");
+    return;
+  }
+
+  /* delete the current message */
+  curmsg = owl_global_get_curmsg(&g);
+  owl_function_delete_and_expunge_message(curmsg);
+  if (exclaim_success)
+    owl_function_makemsg("Message deleted and expunged");
+}
+
 /* if move_after is 1, moves after the delete */
 void owl_function_deletecur(int move_after)
@@ -1664,4 +1694,17 @@
 }
 
+void owl_function_delete_and_expunge_by_id(int id, bool exclaim_success)
+{
+  const owl_messagelist *ml = owl_global_get_msglist(&g);
+  int msg = owl_messagelist_get_index_by_id(ml, id);
+  if (msg < 0) {
+    owl_function_error("No message with id %d: unable to delete", id);
+  } else {
+    owl_function_delete_and_expunge_message(msg);
+    if (exclaim_success)
+      owl_function_makemsg("Message deleted and expunged");
+  }
+}
+
 /* note: this applies to global message list, not to view.
  * If flag is 1, deletes.  If flag is 0, undeletes. */
Index: messagelist.c
===================================================================
--- messagelist.c	(revision 901cee9b7ebc203aee860a9c5fc3849ed3527532)
+++ messagelist.c	(revision efeec7f945a0024cc21af30c2e6c2110bb5d3c6b)
@@ -30,7 +30,7 @@
 }
 
-owl_message *owl_messagelist_get_by_id(const owl_messagelist *ml, int target_id)
+int owl_messagelist_get_index_by_id(const owl_messagelist *ml, int target_id)
 {
-  /* return the message with id == 'id'.  If it doesn't exist return NULL. */
+  /* return the message index with id == 'id'.  If it doesn't exist return -1. */
   int first, last, mid, msg_id;
   owl_message *m;
@@ -43,5 +43,5 @@
     msg_id = owl_message_get_id(m);
     if (msg_id == target_id) {
-      return(m);
+      return mid;
     } else if (msg_id < target_id) {
       first = mid + 1;
@@ -50,5 +50,13 @@
     }
   }
-  return(NULL);
+  return -1;
+}
+
+owl_message *owl_messagelist_get_by_id(const owl_messagelist *ml, int target_id)
+{
+  /* return the message with id == 'id'.  If it doesn't exist return NULL. */
+  int n = owl_messagelist_get_index_by_id(ml, target_id);
+  if (n < 0) return NULL;
+  return ml->list->pdata[n];
 }
 
@@ -71,4 +79,9 @@
   owl_message_unmark_delete(ml->list->pdata[n]);
   return(0);
+}
+
+void owl_messagelist_delete_and_expunge_element(owl_messagelist *ml, int n)
+{
+  owl_message_delete(g_ptr_array_remove_index(ml->list, n));
 }
 
