diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala
index af315646..77c0af73 100644
--- a/src/engine/imap-db/imap-db-folder.vala
+++ b/src/engine/imap-db/imap-db-folder.vala
@@ -2041,6 +2041,45 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
         Gee.List<GMime.Part>? attachments, Cancellable? cancellable) throws Error {
         do_save_attachments_db(cx, message_id, attachments, db, cancellable);
     }
+
+    struct TnefFile {
+        string name;
+        int offset;
+        int size;
+    }
+
+    static Gee.ArrayList<TnefFile?> tnef_extract_attachments(DataInputStream mis) {
+        var out = new Gee.ArrayList<TnefFile?>();
+        TnefFile file = TnefFile();
+        try {
+            mis.skip(2);
+            while(true) {
+                mis.skip(1);
+                uint16 type = mis.read_int16();
+                mis.skip(2);
+                int len = mis.read_int32();
+                if(type ==  0x8010) { // Attachment File name
+                    uint8[] fn = new uint8[len];
+                    mis.read(fn);
+                    file.name = (string) fn;
+                } else if(type == 0x800f) { // Attachment Content
+                    file.offset = (int) mis.tell();
+                    file.size = len;
+                    mis.skip(len);
+                } else if(type == 0x9005) { // End of attachment
+                    out.add(file);
+                    file = TnefFile();
+                    mis.skip(len);
+                } else {
+                    mis.skip(len);
+                }
+                mis.skip(2);
+            }
+        } catch(IOError err) {
+            // EOF
+        }
+        return out;
+    }
     
     public static void do_save_attachments_db(Db.Connection cx, int64 message_id,
         Gee.List<GMime.Part>? attachments, ImapDB.Database db, Cancellable? cancellable) throws Error {
@@ -2065,7 +2104,6 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
             stream.set_owner(false);
             if (attachment_data != null)
                 attachment_data.write_to_stream(stream); // data is null if it's 0 bytes
-            uint filesize = byte_array.len;
             
             // convert into DispositionType enum, which is stored as int
             // (legacy code stored UNSPECIFIED as NULL, which is zero, which is ATTACHMENT, so preserve
@@ -2075,91 +2113,109 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
             if (disposition_type == Mime.DispositionType.UNSPECIFIED)
                 disposition_type = Mime.DispositionType.ATTACHMENT;
             
-            // Insert it into the database.
-            Db.Statement stmt = cx.prepare("""
-                INSERT INTO MessageAttachmentTable (message_id, filename, mime_type, filesize, disposition, content_id, description)
-                VALUES (?, ?, ?, ?, ?, ?, ?)
-                """);
-            stmt.bind_rowid(0, message_id);
-            stmt.bind_string(1, filename);
-            stmt.bind_string(2, mime_type);
-            stmt.bind_uint(3, filesize);
-            stmt.bind_int(4, disposition_type);
-            stmt.bind_string(5, content_id);
-            stmt.bind_string(6, description);
-            
-            int64 attachment_id = stmt.exec_insert(cancellable);
+            Memory.ByteBuffer bytebuf = new Memory.ByteBuffer.from_byte_array(byte_array);
+            var dis = new DataInputStream(bytebuf.get_input_stream());
+            dis.set_byte_order(DataStreamByteOrder.LITTLE_ENDIAN);
+
+            if (dis.read_int32() == 0x223e9f78) { // TNEF magic header
+                foreach(TnefFile file in tnef_extract_attachments(dis)) {
+                    string? mime = Mime.ContentType.guess_type(file.name, bytebuf).get_mime_type();
+                    Bytes chunk = bytebuf.get_bytes()[file.offset:file.offset+file.size];
+                    do_save_attachment_db(cx, message_id, db, file.name, mime, chunk, Mime.DispositionType.ATTACHMENT, null, null, cancellable);
+                }
+            } else {
+                do_save_attachment_db(cx, message_id, db, filename, mime_type, bytebuf.get_bytes(), disposition_type, content_id, description, cancellable);
+            }
+        }
+    }
+
+    private static void do_save_attachment_db(Db.Connection cx, int64 message_id, ImapDB.Database db, string? filename, string? mime_type,
+            Bytes content, Mime.DispositionType disposition_type, string? content_id, string? description, Cancellable? cancellable) throws Error{
+        uint filesize = content.length;
+        // Insert it into the database.
+        Db.Statement stmt = cx.prepare("""
+            INSERT INTO MessageAttachmentTable (message_id, filename, mime_type, filesize, disposition, content_id, description)
+            VALUES (?, ?, ?, ?, ?, ?, ?)
+            """);
+        stmt.bind_rowid(0, message_id);
+        stmt.bind_string(1, filename);
+        stmt.bind_string(2, mime_type);
+        stmt.bind_uint(3, filesize);
+        stmt.bind_int(4, disposition_type);
+        stmt.bind_string(5, content_id);
+        stmt.bind_string(6, description);
+        
+        int64 attachment_id = stmt.exec_insert(cancellable);
+        
+        File saved_file = ImapDB.Attachment.generate_file(db.db_file.get_parent(), message_id,
+            attachment_id, filename);
+        
+        // On the off-chance this is marked for deletion, unmark it
+        try {
+            stmt = cx.prepare("""
+                DELETE FROM DeleteAttachmentFileTable
+                WHERE filename = ?
+            """);
+            stmt.bind_string(0, saved_file.get_path());
             
-            File saved_file = ImapDB.Attachment.generate_file(db.db_file.get_parent(), message_id,
-                attachment_id, filename);
+            stmt.exec(cancellable);
+        } catch (Error err) {
+            debug("Unable to delete from DeleteAttachmentFileTable: %s", err.message);
             
-            // On the off-chance this is marked for deletion, unmark it
+            // not a deal-breaker, fall through
+        }
+        
+        debug("Saving attachment to %s", saved_file.get_path());
+        
+        try {
+            // create directory, but don't throw exception if already exists
             try {
-                stmt = cx.prepare("""
-                    DELETE FROM DeleteAttachmentFileTable
-                    WHERE filename = ?
-                """);
-                stmt.bind_string(0, saved_file.get_path());
-                
-                stmt.exec(cancellable);
-            } catch (Error err) {
-                debug("Unable to delete from DeleteAttachmentFileTable: %s", err.message);
-                
-                // not a deal-breaker, fall through
+                saved_file.get_parent().make_directory_with_parents(cancellable);
+            } catch (IOError ioe) {
+                // fall through if already exists
+                if (!(ioe is IOError.EXISTS))
+                    throw ioe;
             }
             
-            debug("Saving attachment to %s", saved_file.get_path());
+            // REPLACE_DESTINATION doesn't seem to work as advertised all the time ... just
+            // play it safe here
+            if (saved_file.query_exists(cancellable))
+                saved_file.delete(cancellable);
+            
+            // Create the file where the attachment will be saved and get the output stream.
+            FileOutputStream saved_stream = saved_file.create(FileCreateFlags.REPLACE_DESTINATION,
+                cancellable);
+            
+            // Save the data to disk and flush it.
+            size_t written;
+            if (filesize != 0)
+                saved_stream.write_all(content.get_data()[0:filesize], out written, cancellable);
+            
+            saved_stream.flush(cancellable);
+        } catch (Error error) {
+            // An error occurred while saving the attachment, so lets remove the attachment from
+            // the database and delete the file (in case it's partially written)
+            debug("Failed to save attachment %s: %s", saved_file.get_path(), error.message);
             
             try {
-                // create directory, but don't throw exception if already exists
-                try {
-                    saved_file.get_parent().make_directory_with_parents(cancellable);
-                } catch (IOError ioe) {
-                    // fall through if already exists
-                    if (!(ioe is IOError.EXISTS))
-                        throw ioe;
-                }
-                
-                // REPLACE_DESTINATION doesn't seem to work as advertised all the time ... just
-                // play it safe here
-                if (saved_file.query_exists(cancellable))
-                    saved_file.delete(cancellable);
-                
-                // Create the file where the attachment will be saved and get the output stream.
-                FileOutputStream saved_stream = saved_file.create(FileCreateFlags.REPLACE_DESTINATION,
-                    cancellable);
-                
-                // Save the data to disk and flush it.
-                size_t written;
-                if (filesize != 0)
-                    saved_stream.write_all(byte_array.data[0:filesize], out written, cancellable);
-                
-                saved_stream.flush(cancellable);
-            } catch (Error error) {
-                // An error occurred while saving the attachment, so lets remove the attachment from
-                // the database and delete the file (in case it's partially written)
-                debug("Failed to save attachment %s: %s", saved_file.get_path(), error.message);
-                
-                try {
-                    saved_file.delete();
-                } catch (Error delete_error) {
-                    debug("Error attempting to delete partial attachment %s: %s", saved_file.get_path(),
-                        delete_error.message);
-                }
-                
-                try {
-                    Db.Statement remove_stmt = cx.prepare(
-                        "DELETE FROM MessageAttachmentTable WHERE id=?");
-                    remove_stmt.bind_rowid(0, attachment_id);
-                    
-                    remove_stmt.exec();
-                } catch (Error remove_error) {
-                    debug("Error attempting to remove added attachment row for %s: %s",
-                        saved_file.get_path(), remove_error.message);
-                }
+                saved_file.delete();
+            } catch (Error delete_error) {
+                debug("Error attempting to delete partial attachment %s: %s", saved_file.get_path(),
+                    delete_error.message);
+            }
+            
+            try {
+                Db.Statement remove_stmt = cx.prepare(
+                    "DELETE FROM MessageAttachmentTable WHERE id=?");
+                remove_stmt.bind_rowid(0, attachment_id);
                 
-                throw error;
+                remove_stmt.exec();
+            } catch (Error remove_error) {
+                debug("Error attempting to remove added attachment row for %s: %s",
+                    saved_file.get_path(), remove_error.message);
             }
+            
+            throw error;
         }
     }
     
