Logging Sent Emails with Advanced ETL Processor
Logging sent emails requires two records: the original message and the metadata needed to find it. Advanced ETL Processor generates a unique Message-ID for the outgoing email and makes it available through a variable. Save the raw message as an .eml file, then write the Message-ID, business identifiers, and file path to a database. A mailbox alone can do the filing, but it is not much of a relational database (despite years of trying).
An email audit log needs the message and its identifiers
The Send Email action exposes the values used in this workflow after the message is sent:
#MessageID#contains the unique identifier for the outgoing message.#RawMessage#contains the complete email-format message, including its headers and body.#To#contains the recipient address.#Subject#contains the sent subject.
Enable these four entries on the action’s Variables tab. The Message-ID becomes the durable matching key. The raw message provides the evidence behind the row.
This audit record is separate from the action’s diagnostic logging option. The product documentation recommends diagnostic logging only for debugging because it can create very large log files.
Build the sent-email logging workflow in seven steps
- Send the message. Configure the Send Email action with the SMTP or Microsoft Graph connection, recipient, subject, body, and attachments.
- Expose the output variables. Enable Message ID, Raw Message, To, and Subject on the Variables tab.
- Create a filename-safe identifier. Use a Set Variables action to remove characters from
#MessageID#that should not appear in a Windows filename. - Create a dated archive folder. The tutorial uses
C:\DATA\<CurrentDate>so one directory does not become a museum of every email ever sent. - Save the raw message. Use Save String to write
#RawMessage#to an.emlfile named with the cleaned identifier. - Insert the audit row. Use the SQL Script action with an existing database connection and an embedded statement.
- Verify both outputs. Open the saved
.emlfile and query the database row before scheduling the package.
Clean the Message-ID before using it as a filename
The tutorial’s mail server returns a Message-ID with angle brackets and the @etl-tools.com domain. This calculated Pascal variable removes those parts:
begin
Result:=Replace(GetVariable('#MessageID#'),'<','');
Result:=Replace(Result,'>','');
Result:=Replace(Result,'@etl-tools.com','');
end; The resulting #CustomMessageID# is used in this file pattern:
#Folder#\#CustomMessageID#.eml Treat the script as an example, not a universal filename policy. Use your own Message-ID domain and remove any other characters your storage platform rejects. Keep the original #MessageID# unchanged in the database so later comparisons use the value produced by the mail workflow.
Store the message beside its business identifiers
The workflow inserts seven values into EMAIL_LOG. SQL Server generates the row ID and email date. The variable mapping connects the archived message to the business record and leaves room for reply correlation.
| Field | Runtime value |
|---|---|
ID | Generated by the table’s IDENTITY(1,1) definition. |
EMAIL_DATE | Generated by the DF_EMAIL_LOG_EMAIL_DATE default. |
EMAIL_TYPE | #EMAIL_TYPE# |
ORG_CODE | #ORG_FROM# |
NATIONAL_CODE | #ORG_TO# |
INVOICE_NUMBER | #INVOICE_NUMBER# |
FILE_NAME | #MESSAGE_FILE_NAME# |
MESSAGE_ID | #MessageID# |
IN_REPLY_TO | #IN-REPLY-TO# |
Keep the variable names and database column names distinct. The mapping is explicit, which is less exciting than guessing and considerably easier to support.
Create the SQL Server email log table
The workflow uses this table definition. It creates an identity primary key and applies the SQL Server date when EMAIL_DATE is omitted from an insert.
CREATE TABLE [dbo].[EMAIL_LOG](
[ID] [int] IDENTITY(1,1) NOT NULL,
[EMAIL_TYPE] [varchar](150) NULL,
[EMAIL_DATE] [date] NULL,
[ORG_CODE] [varchar](50) NULL,
[NATIONAL_CODE] [varchar](50) NULL,
[INVOICE_NUMBER] [varchar](50) NULL,
[FILE_NAME] [varchar](250) NULL,
[MESSAGE_ID] [varchar](250) NULL,
[IN_REPLY_TO] [varchar](250) NULL,
CONSTRAINT [PK_EMAIL_LOG] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[EMAIL_LOG] ADD CONSTRAINT [DF_EMAIL_LOG_EMAIL_DATE] DEFAULT (getdate()) FOR [EMAIL_DATE]
GO The date type records the calendar date, not a time of day. Change the design before production if the audit requirement needs a precise send time.
Insert the runtime values with the SQL Script action
The workflow uses this statement:
INSERT INTO [EMAIL_LOG]
([EMAIL_TYPE]
,[ORG_CODE]
,[NATIONAL_CODE]
,[INVOICE_NUMBER]
,[FILE_NAME]
,[MESSAGE_ID]
,[IN_REPLY_TO])
VALUES
('#EMAIL_TYPE#'
,'#ORG_FROM#'
,'#ORG_TO#'
,'#INVOICE_NUMBER#'
,'#MESSAGE_FILE_NAME#'
,'#MessageID#'
,'#IN-REPLY-TO#') Set Replace Variables to True. With it disabled, SQL Server receives the literal placeholder text instead of the runtime values.
The values are quoted in the supplied statement. Do not pass untrusted values into direct SQL substitution unchanged. Escape apostrophes and other database-sensitive characters before this action, then test the resulting statement with representative business data.
Test the archive and database row together
- Confirm the package finishes without an action error.
- Open the dated folder and check that the
.emlfilename uses the cleaned identifier. - Open the file and confirm its headers include the same Message-ID stored in the database.
- Query
EMAIL_LOGand check the organisation codes, invoice number, message identifiers, and archive path. - Test business values containing apostrophes and any non-ASCII text your real workflow accepts.
- Keep an unmatched or failed-message path so a logging error does not disappear into the same mailbox it was meant to document.
Run these checks with a few test messages before scheduling the package. Ten controlled rows are easier to inspect than ten thousand confident mistakes.
Watch the complete sent-email logging tutorial
The audit row becomes the reply-tracking key
A reply normally carries the original Message-ID in its In-Reply-To header. Store the sent value now, then the next workflow can compare it with incoming messages. This is more dependable than matching subjects, which users and email software are free to edit.
Read the reply-tracking workflow guide for the next step. For the email standard behind these fields, see RFC 5322 section 3.6.4 and Microsoft’s Graph message resource.
Continue through the email automation workflow
Return to the Email Automation hub for mailbox, attachment, reporting, and Microsoft 365 guides.
Questions about logging sent emails
Why should sent emails be logged in a database?
A database log connects each outgoing message to its business identifiers, archive file, and Message-ID. That record supports audits, troubleshooting, and reply tracking without relying on a user’s Sent folder.
Which Advanced ETL Processor variables are used?
The tutorial enables Message ID, Raw Message, To, and Subject in the Send Email action. Their variables are #MessageID#, #RawMessage#, #To#, and #Subject#.
What format is used to archive the sent message?
The Raw Message value is saved as an .eml file. This retains the message headers and body in a standard email file that can be inspected later.
Why is the Message-ID changed before it becomes a filename?
The tutorial removes angle brackets and the email domain to produce a filename-safe value. Adapt that cleanup for the characters and domain used by your mail server.
Why does the SQL Script action need Replace Variables enabled?
Replace Variables substitutes runtime values such as #EMAIL_TYPE# and #MessageID# into the statement. If it remains disabled, the database receives the placeholder text instead of the intended values.
How does logging help track replies?
Store the outgoing Message-ID in the log. When a reply arrives, compare its In-Reply-To value with that stored identifier to find the original email and business record.
When is a database email log unnecessary?
If one person sends a few messages manually and the mailbox already provides enough history, a separate audit table may add work without adding value. Use it when an unattended workflow needs traceability, database matching, or reply handling.
Build a Searchable Sent-Email Audit Trail
Download the fully functional 30-day trial and test the workflow with your own mail server, archive folder, and database.
Direct link, no registration required.