Issue 227 Mailbox Could Not Be Deleted - edmozley/freeitsm GitHub Wiki

A mailbox could not be deleted

Reported: #227 by bigtrodat, October 2026 ยท Module: Tickets ยท Fixed in: 4.5.0 (changelog #2663)


What you saw

Tickets โ†’ Settings โ†’ Mailboxes โ†’ Delete on a mailbox that had ever received mail failed with:

Error deleting mailbox: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or
update a parent row: a foreign key constraint fails (`freeitsm`.`emails`, CONSTRAINT
`fk_emails_mailbox` FOREIGN KEY (`mailbox_id`) REFERENCES `target_mailboxes` (`id`))

Deleting every ticket and emptying the trash did not help. Database Verification and Debug Tools both said all was well โ€” correctly, because nothing in the database was broken.


What was actually wrong

Every email FreeITSM imports remembers which mailbox it came from (emails.mailbox_id). That is how a reply on a ticket knows which address to go out from. The database refuses to delete a mailbox while any email still points at it โ€” which is right โ€” but the Delete button simply tried, and showed the database's refusal as it came.

Why emptying the trash did not clear it

Purging a ticket deletes the emails on that ticket. It cannot touch mail that never became a ticket: a sender the whitelist turned away, a message still waiting, an email whose ticket was removed by some older route. Those emails have no ticket, so no ticket purge ever reaches them, and they kept the mailbox pinned.

It was three tables, not one

Five tables point at a mailbox:

Table On delete, before Now
emails refused moved to another mailbox, or cleared (see below)
mailbox_email_whitelist refused deleted with the mailbox
mailbox_activity_log refused deleted with the mailbox
email_send_log link cleared unchanged
calendar_connections link cleared unchanged

The error named only emails because that is the first one the database checked. With the emails out of the way, the whitelist or the activity log would have refused next.


The fix

Delete now opens a dialog that first asks what still uses the mailbox:

  • how many emails are on tickets, and how many are on no ticket;
  • a Move its emails to list โ€” every other mailbox of the same company, plus shared mailboxes, plus No mailbox;
  • what the chosen option will cost, in red, before you press Delete;
  • a reminder that unticking Active stops a mailbox collecting mail with nothing lost.

Pressing Delete then does everything in one transaction โ€” if any step fails, nothing has changed:

  1. Moving: every email of the mailbox is moved to the chosen one. Tickets keep their emails, and replies on them go out from the new mailbox.
  2. No mailbox: emails on tickets stay on their tickets with no mailbox recorded; emails on no ticket are deleted, with their attachments.
  3. The mailbox's whitelist and activity log are deleted.
  4. If Knowledge article sharing sent from this mailbox, that setting is blanked so Knowledge settings asks for another.
  5. The mailbox is deleted.

โš ๏ธ Why the dialog warns about No mailbox. A ticket's replies go out from the mailbox on its emails. There is no default mailbox to fall back on, so a ticket whose emails have no mailbox can no longer be replied to by email โ€” the reply fails with "Could not determine mailbox for this ticket". Moving the emails avoids that, and is why moving is offered first.

๐Ÿ”‘ Only mailboxes of the same company are offered. Moving one company's emails onto another company's mailbox would send that company's replies from someone else's address. The server checks this too, not only the list.

No database change was needed, so there is nothing to run after upgrading.


Files changed

File Change
๐ŸŸข api/tickets/delete_mailbox.php a preview call that counts and lists move targets; the delete itself as one transaction
๐Ÿ”ต tickets/settings/index.php the delete dialog in place of a plain "Are you sure?"
๐Ÿ”ต lang/en/tickets.php the dialog's words (tickets.settings.modals.mailbox_delete)

How it was proved

Through the real endpoint, against throwaway mailboxes and emails that the test removes afterwards:

  • the preview counted 1 email on a ticket and 2 on none (one with no ticket, one whose ticket no longer exists), offered the other mailbox and not the one being deleted, and changed nothing;
  • moving to the mailbox being deleted was refused;
  • No mailbox: the mailbox, both loose emails, the attachment, the whitelist row and the activity row were gone, and the ticket's email was still there with its mailbox cleared;
  • moving: both emails were found on the chosen mailbox afterwards.

The dialog was then driven in a browser: it opened, showed the counts, and switching to No mailbox drew both warnings.


What this means for you

If you hit this, upgrade and press Delete again. Choose where the emails go โ€” or untick Active instead if you only want the mailbox to stop collecting mail.

The same kind of raw database error can still appear when deleting something else that is in use, such as a department. A general answer โ€” a plain message that says what is still using the record โ€” is planned separately.


Related: Mailbox authentication ยท Basic IMAP mailboxes ยท Tickets settings developer guide ยท Bugs resolved