Skip to content

Database Schema

SendGrail creates four custom database tables to store connection configurations, email logs, tracking events, and routing rules. All tables use the standard WordPress table prefix (typically wp_).

Overview

TablePurpose
wp_sendgrail_connectionsSMTP connection configurations
wp_sendgrail_email_logsEmail delivery log entries
wp_sendgrail_email_eventsTracking events (sent, opened, clicked, failed)
wp_sendgrail_email_routesConditional email routing rules

INFO

Migrations run automatically on plugin activation and on version updates. The current database schema version is tracked in the WordPress options table under the key sendgrail_db_version.


wp_sendgrail_connections

Stores SMTP connection configurations. Each row represents a single SMTP provider connection.

ColumnTypeNullableDefaultDescription
idBIGINT(20) UNSIGNEDNoAuto-incrementPrimary key
nameVARCHAR(255)NoDisplay name for the connection
providerVARCHAR(100)NoProvider slug (e.g., gmail, sendgrid, ses)
hostVARCHAR(255)NoSMTP server hostname
portINT(5) UNSIGNEDNo587SMTP port number
encryptionVARCHAR(10)NotlsEncryption type: tls, ssl, or none
from_emailVARCHAR(255)NoSender email address
from_nameVARCHAR(255)YesNULLSender display name
authTINYINT(1)No1Whether SMTP authentication is required
usernameVARCHAR(255)YesNULLSMTP authentication username
passwordTEXTYesNULLEncrypted SMTP password
is_enabledTINYINT(1)No1Whether the connection is active
is_defaultTINYINT(1)No0Whether this is the default connection
created_atDATETIMENoCURRENT_TIMESTAMPRecord creation time (UTC)
updated_atDATETIMENoCURRENT_TIMESTAMPLast update time (UTC)

Indexes:

IndexColumnsType
PRIMARYidPrimary
idx_providerproviderIndex
idx_is_enabledis_enabledIndex
idx_is_defaultis_defaultIndex

Security Note

The password column is encrypted using AES-256-CBC with a key derived from the WordPress AUTH_KEY salt. Passwords are never stored in plaintext and are decrypted only at the moment of SMTP authentication.


wp_sendgrail_email_logs

Stores a log entry for every email sent through WordPress wp_mail() while SendGrail is active.

ColumnTypeNullableDefaultDescription
idBIGINT(20) UNSIGNEDNoAuto-incrementPrimary key
connection_idBIGINT(20) UNSIGNEDYesNULLFK to connections table
toTEXTNoRecipient email address(es)
from_emailVARCHAR(255)YesNULLSender email used
from_nameVARCHAR(255)YesNULLSender name used
subjectVARCHAR(255)YesNULLEmail subject line
bodyLONGTEXTYesNULLFull email body (if body logging is enabled)
headersTEXTYesNULLEmail headers as JSON
attachmentsTEXTYesNULLAttachment file paths as JSON array
statusVARCHAR(20)NopendingDelivery status: pending, sent, failed
error_messageTEXTYesNULLError message if delivery failed
tracking_idVARCHAR(64)YesNULLUnique ID for open/click tracking
retriesTINYINT(3) UNSIGNEDNo0Number of fallback retry attempts
created_atDATETIMENoCURRENT_TIMESTAMPWhen the email was queued (UTC)
updated_atDATETIMENoCURRENT_TIMESTAMPLast status update (UTC)

Indexes:

IndexColumnsType
PRIMARYidPrimary
idx_connection_idconnection_idIndex
idx_statusstatusIndex
idx_tracking_idtracking_idUnique
idx_created_atcreated_atIndex
idx_status_createdstatus, created_atComposite

wp_sendgrail_email_events

Records granular tracking events associated with email log entries. Each email can have multiple events over its lifecycle.

ColumnTypeNullableDefaultDescription
idBIGINT(20) UNSIGNEDNoAuto-incrementPrimary key
email_log_idBIGINT(20) UNSIGNEDNoFK to email_logs table
typeVARCHAR(20)NoEvent type: sent, opened, clicked, failed
metadataTEXTYesNULLAdditional event data as JSON
ip_addressVARCHAR(45)YesNULLIP address of the event trigger
user_agentTEXTYesNULLUser agent string (for open/click events)
created_atDATETIMENoCURRENT_TIMESTAMPWhen the event occurred (UTC)

Indexes:

IndexColumnsType
PRIMARYidPrimary
idx_email_log_idemail_log_idIndex
idx_typetypeIndex
idx_created_atcreated_atIndex
idx_log_typeemail_log_id, typeComposite

Event Types:

TypeDescriptionMetadata
sentEmail was successfully handed off to the SMTP server
openedRecipient loaded the tracking pixel{"count": 3} for repeated opens
clickedRecipient clicked a tracked link{"url": "https://..."} original link URL
failedDelivery failed{"error": "Connection timed out"}

wp_sendgrail_email_routes

Stores conditional routing rules that determine which SMTP connection handles an email based on matching criteria.

ColumnTypeNullableDefaultDescription
idBIGINT(20) UNSIGNEDNoAuto-incrementPrimary key
nameVARCHAR(255)NoDisplay name for the rule
fieldVARCHAR(50)NoField to match against
operatorVARCHAR(20)NoComparison operator
valueVARCHAR(255)NoValue to compare against
connection_idBIGINT(20) UNSIGNEDNoFK to connections table
priorityINT(11)No0Sort order (lower number = higher priority)
is_enabledTINYINT(1)No1Whether the rule is active
created_atDATETIMENoCURRENT_TIMESTAMPRecord creation time (UTC)
updated_atDATETIMENoCURRENT_TIMESTAMPLast update time (UTC)

Indexes:

IndexColumnsType
PRIMARYidPrimary
idx_connection_idconnection_idIndex
idx_prioritypriorityIndex
idx_is_enabledis_enabledIndex
idx_enabled_priorityis_enabled, priorityComposite

Supported Fields:

Field SlugDescription
from_emailFull sender email address
from_domainDomain part of the sender email
to_emailFull recipient email address
to_domainDomain part of the recipient email
subjectEmail subject line

Supported Operators:

OperatorDescription
equalsExact match (case-insensitive)
containsSubstring match
starts_withValue starts with the specified string
ends_withValue ends with the specified string
regexRegular expression match

Entity Relationships

wp_sendgrail_connections
  ├── wp_sendgrail_email_logs (connection_id → id)
  └── wp_sendgrail_email_routes (connection_id → id)

wp_sendgrail_email_logs
  └── wp_sendgrail_email_events (email_log_id → id)

TIP

Foreign key constraints are not enforced at the database level (for compatibility with all MySQL/MariaDB versions). Referential integrity is maintained at the application layer. Deleting a connection will not cascade-delete its logs or routes.

Version Tracking

The database schema version is stored as a WordPress option:

php
get_option('sendgrail_db_version'); // e.g., "1.0.0"

Migrations are executed automatically when SendGrail detects that the stored version is lower than the plugin's current version. This check runs on every admin page load via the plugins_loaded hook.

Released under the GPL-3.0 License.