Billionmail/BillionMail · warning
mailbox %s already exists
Error message
mailbox %s already exists
What it means
Add inserts the new mailbox row into the 'mailbox' table; if the DB rejects the insert with a duplicate/unique constraint violation, it is translated into this friendly 'mailbox %s already exists' error instead of surfacing the raw SQL error.
Source
Thrown at core/internal/service/mail_boxes/mail_boxes.go:49
if err != nil {
err = fmt.Errorf("Generate password md5-crypt failed: %w", err)
return
}
mailbox.Username = strings.ToLower(mailbox.Username)
mailbox.LocalPart = strings.ToLower(mailbox.LocalPart)
mailbox.Domain = strings.ToLower(mailbox.Domain)
now := time.Now().Unix()
mailbox.CreateTime = now
mailbox.UpdateTime = now
mailbox.Active = 1
mailbox.Maildir = fmt.Sprintf("%s@%s/", mailbox.LocalPart, mailbox.Domain)
_, err = g.DB().Model("mailbox").Ctx(ctx).Insert(mailbox)
if err != nil {
if strings.Contains(err.Error(), "duplicate") || strings.Contains(err.Error(), "unique") {
return fmt.Errorf("mailbox %s already exists", mailbox.Username)
}
return err
}
// maildirsize
if e2 := ensureMaildirAndQuotaFile(ctx, mailbox); e2 != nil {
g.Log().Warning(ctx, "ensureMaildirAndQuotaFile failed", e2)
}
return nil
}
func Update(ctx context.Context, mailbox *v1.Mailbox) (err error) {
mailbox.UpdateTime = time.Now().Unix()
if mailbox.Password != "" {
mailbox.PasswordEncode = PasswdEncode(ctx, mailbox.Password)
mailbox.Password, err = PasswdMD5Crypt(ctx, mailbox.Password)
if err != nil {
err = fmt.Errorf("Generate password md5-crypt failed: %w", err)View on GitHub (pinned to fc36c76c05)
Solutions
- Check mailbox existence (SELECT by lowercased username) before calling Add
- Catch this error and surface a friendly 'address already in use' message to the end user
- Handle concurrent creation with upsert (INSERT ... ON CONFLICT DO NOTHING) or a unique-check inside a transaction
- Purge soft-deleted/duplicate rows that still hold the unique key
Example fix
// before
_, err = g.DB().Model("mailbox").Ctx(ctx).Insert(mailbox)
if err != nil {
if strings.Contains(err.Error(), "duplicate") || strings.Contains(err.Error(), "unique") {
return fmt.Errorf("mailbox %s already exists", mailbox.Username)
}
return err
}
// after
count, err := g.DB().Model("mailbox").Ctx(ctx).Where("username = ?", mailbox.Username).Count()
if err != nil {
return err
}
if count > 0 {
return fmt.Errorf("mailbox %s already exists", mailbox.Username)
}
_, err = g.DB().Model("mailbox").Ctx(ctx).Insert(mailbox) Defensive patterns
Strategy: try-catch
Validate before calling
count, err := g.DB().Model("mailbox").Ctx(ctx).
Where("username = ?", strings.ToLower(username)).Count()
if err != nil {
return err
}
if count > 0 {
return fmt.Errorf("mailbox %s already exists", username)
} Try / catch
err := mail_boxes.Add(ctx, mailbox)
if err != nil && strings.Contains(err.Error(), "already exists") {
// friendly UX: surface 'address already in use' to the user
return consts.NewDuplicateMailboxError(mailbox.Username)
}
if err != nil {
return err
} Prevention
- Always lowercase usernames before existence checks and inserts
- Use upsert / ON CONFLICT for idempotent creation flows
- Make import scripts idempotent (skip existing usernames)
- Purge soft-deleted rows that still hold the unique key
When it happens
Trigger: Inserting a mailbox whose username already exists in the mailbox table (unique constraint); two concurrent Add calls racing to create the same address; re-running mailbox creation for an existing user; soft-deleted rows still occupying the unique key.
Common situations: User double-submits the create-mailbox form; import scripts re-run without idempotency; case-sensitivity mismatch — usernames are lowercased before insert but callers checked existence with mixed case; leftover row after an alias/domain rename.
Related errors
- query password failed: %w
- failed to get all domains: %w
- fail to check domain: %w
- failed to get all emails: %w
- failed to get all mailboxes: %w
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/7e17f7ebd84c0ce2.
Report an issue: GitHub.