Skip to content

Draft attachments are lost when a draft is synced to the IMAP Drafts folder and reopened (regression in 5.10.x) #13170

Description

@hermann1505

Steps to reproduce

  1. Compose a new message.
  2. Attach one or more local files (drag & drop / upload). The upload succeeds — POST /apps/mail/api/attachments201, blob is stored, an oc_mail_attachments row is created.
  3. Do not send. Let the composer auto-save and/or navigate away, so the draft is pushed to the IMAP Drafts mailbox:
    • POST /apps/mail/api/drafts201
    • POST /apps/mail/api/drafts/move/{id}202
  4. Open the Drafts folder and reopen that draft.

Expected behavior

The draft reopens with the attachment(s) still attached, ready to send.

Actual behavior

  1. Compose a new message.
  2. Attach one or more local files (drag & drop / upload). The upload succeeds — POST /apps/mail/api/attachments201, blob is stored, an oc_mail_attachments row is created.
  3. Do not send. Let the composer auto-save and/or navigate away, so the draft is pushed to the IMAP Drafts mailbox:
    • POST /apps/mail/api/drafts201
    • POST /apps/mail/api/drafts/move/{id}202
  4. Open the Drafts folder and reopen that draft.

Expected behaviour

The draft reopens with the attachment(s) still attached, ready to send.

Actual behaviour

  • The attachment is gone from the reopened draft.
  • The locally-uploaded attachment row is left orphaned (oc_mail_attachments.local_message_id = NULL) and its appdata blob is stranded.
  • The corresponding message cached for the Drafts mailbox has flag_attachments = 0 — i.e. the attachment was not carried into the IMAP draft.
  • Continuing to edit/re-save the reopened draft throws on the server:
InvalidArgumentException: Attachment does not have a type
  at OCA\Mail\Service\Attachment\AttachmentService->handleAttachments()   lib/Service/Attachment/AttachmentService.php:253
  from OCA\Mail\Service\DraftsService->handleAttachments()                 lib/Service/DraftsService.php:118
  via OCA\Mail\Controller\DraftsController->saveMessage()                  lib/Controller/DraftsController.php:127
  POST /apps/mail/api/drafts

The check at AttachmentService.php:253 is:

foreach ($attachments as $attachment) {
    if (!isset($attachment['type'])) {
        throw new InvalidArgumentException('Attachment does not have a type');
    }
    ...

so the frontend is submitting at least one attachment object without a type property when continuing a draft that was round-tripped through the IMAP Drafts folder.

Works as a contrast (no IMAP Drafts round-trip)

Composing → attaching → sending in one sitting works correctly and the recipient gets the attachment. The flow that succeeds goes straight to the outbox without a drafts/move:

POST /apps/mail/api/attachments      201   (xN)
POST /apps/mail/api/drafts           201
POST /apps/mail/api/outbox/from-draft/{id}  201
POST /apps/mail/api/outbox/{id}      202   (sent, with attachments)

The problem only manifests when the draft is saved to / reopened from the IMAP Drafts mailbox.

Regression window

The Attachment does not have a type error first appears in our logs immediately after upgrading into the 5.10.x line (first seen the days following the 5.10.0 release) and never occurred on 5.9.x. This looks like a regression introduced in 5.10.0.

Side effect

Because the linking step throws, every failed attempt leaves an orphaned oc_mail_attachments row (local_message_id = NULL) plus its appdata blob. These accumulate over time (we found 91 stranded blobs) and are never garbage-collected.

Mail app version

5.10.3

Nextcloud version

34.0.0

Mailserver or service

IMAP/SMTP: Dovecot/Exim, app-password auth (auth verified healthy — sending and IMAP login both work)

Operating system

Debian (Linux 6.12) / Docker (nextcloud:34-apache)

PHP engine version

Other

Nextcloud memory caching

'memcache.local' => '\OC\Memcache\APCu',

Web server

Apache (supported)

Database

MariaDB

Additional info

PHP 8.4.22
MariaDB 11.8

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions