package db import "time" // InsertEmailLog mirrors the EmailLog row creation in EmailRelay.log_email. Returns the // new row's id (needed before recipient/attachment child rows can be inserted). func (d *DB) InsertEmailLog(l EmailLog) (int64, error) { res, err := d.Exec(`INSERT INTO esrv_email_logs (message_id, timestamp, peer_ip, mail_from, to_address, cc_addresses, bcc_addresses, subject, email_headers, message_body, status, dkim_signed, username) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, l.MessageID, l.Timestamp, l.PeerIP, l.MailFrom, l.ToAddress, l.CcAddresses, l.BccAddresses, l.Subject, l.EmailHeaders, l.MessageBody, l.Status, l.DKIMSigned, l.Username) if err != nil { return 0, err } return res.LastInsertId() } // InsertEmailRecipientLog mirrors one EmailRecipientLog row creation. func (d *DB) InsertEmailRecipientLog(l EmailRecipientLog) error { _, err := d.Exec(`INSERT INTO esrv_email_recipient_logs (email_log_id, recipient, recipient_type, status, error_code, error_message, server_response) VALUES (?, ?, ?, ?, ?, ?, ?)`, l.EmailLogID, l.Recipient, l.RecipientType, l.Status, l.ErrorCode, l.ErrorMessage, l.ServerResponse) return err } // UpdateEmailRecipientLogStatus resolves a placeholder "queued" recipient row (written // at accept time, before the relay queue worker has actually attempted delivery) to // its real outcome — matched by (email_log_id, recipient), not a stored row id, since // EnqueueForDelivery never needs to thread individual recipient-log ids through the // queue table. The status='queued' guard means this can never overwrite an // already-resolved (e.g. local-delivery) row for the same address. func (d *DB) UpdateEmailRecipientLogStatus(emailLogID int64, recipient, status, errorCode, errorMessage, serverResponse string) error { _, err := d.Exec(`UPDATE esrv_email_recipient_logs SET status = ?, error_code = ?, error_message = ?, server_response = ? WHERE email_log_id = ? AND recipient = ? AND status = 'queued'`, status, errorCode, errorMessage, serverResponse, emailLogID, recipient) return err } // UpdateEmailLogStatus overwrites the parent esrv_email_logs row's stored overall // status — called by the relay queue worker once a domain group resolves, so // dashboard.html's "Recent Email Activity" (which reads this stored snapshot, not a // live recompute) reflects the outcome instead of staying "queued" forever. func (d *DB) UpdateEmailLogStatus(id int64, status string) error { _, err := d.Exec(`UPDATE esrv_email_logs SET status = ? WHERE id = ?`, status, id) return err } // InsertEmailAttachment mirrors one EmailAttachment row creation. func (d *DB) InsertEmailAttachment(a EmailAttachment) error { _, err := d.Exec(`INSERT INTO esrv_email_attachments (email_log_id, filename, content_type, file_path, size, uploaded_at) VALUES (?, ?, ?, ?, ?, ?)`, a.EmailLogID, a.Filename, a.ContentType, a.FilePath, a.Size, time.Now()) return err }