Guide
Send SQL Server query results by email as CSV
Email SQL Server query results as a CSV file with sp_send_dbmail and SQL Agent: the parameters that matter, the formatting traps, and Express.
Guide
Email SQL Server query results as a CSV file with sp_send_dbmail and SQL Agent: the parameters that matter, the formatting traps, and Express.
The request always sounds small. Someone wants the result of a query in their inbox every morning, as a file they can open in Excel. On SQL Server the built-in answer is Database Mail, called through msdb.dbo.sp_send_dbmail, scheduled by a SQL Server Agent job. It works, it is free, and it has a handful of behaviours that surprise everyone the first time.
Database Mail needs a profile and an SMTP account configured once, usually through the Database Mail wizard in Management Studio. After that, the call looks like this:
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'ops-mail',
@recipients = 'finance@example.com;controller@example.com',
@subject = 'Open orders',
@body = 'Open orders as of this morning are attached.',
@execute_query_database = 'Sales',
@query = N'SET NOCOUNT ON;
SELECT order_id, customer_name, total, created_at
FROM dbo.orders
WHERE status = ''open''',
@attach_query_result_as_file = 1,
@query_attachment_filename = 'open_orders.csv',
@query_result_separator = ',',
@query_result_no_padding = 1,
@query_result_width = 32767;
Wrap it in an Agent job step, attach a schedule to the job, and the email goes out on its own.
SET NOCOUNT ON at the top of the query removes the "rows affected" line that otherwise lands at the bottom of the file.
@query_result_no_padding = 1 stops SQL Server from padding every value with spaces to the column width, which is what makes the default output look like a fixed-width report.
@query_result_width = 32767 raises the line width from the default of 256 characters, after which long rows wrap onto the next line and the file falls apart.
@query_result_header controls the header row. Left on, it produces the column names followed by a line of dashes, which breaks most CSV readers. The usual workaround is to set it to 0 and add the header yourself with a UNION ALL of literal column names on top of the query, casting every column to text so the union is valid.
@exclude_query_output = 1 keeps query errors and messages out of the email body when the job runs unattended.
There is no CSV quoting. A value that contains a comma, a quote or a line break is written as it is, so a customer called "Smith, Jones and Co" shifts every column after it. The fixes are to pick a separator that never appears in the data, often a tab declared as DECLARE @tab char(1) = CHAR(9) and passed as @query_result_separator = @tab, or to quote the values in the query yourself with QUOTENAME(col, '"') or string concatenation.
The attachment size has a ceiling. Database Mail refuses attachments above MaxFileSize, which defaults to 1,000,000 bytes. It can be raised with msdb.dbo.sysmail_configure_sp 'MaxFileSize', '<bytes>', and most mail servers have their own limit above that.
Unicode needs a decision. @query_attachment_filename ending in .csv does not make Excel read the file as UTF-8. Accented names may come out garbled unless the recipient imports the file explicitly.
Failures are quiet. A message that cannot be delivered is visible in msdb.dbo.sysmail_event_log and sysmail_faileditems, not in the job history, so a job can succeed while the email never leaves. Somebody has to look.
The job runs as the Agent service. The query runs in the security context of the job owner, and that owner often turns out to be the person who created the job and left the company, which is when the job stops.
On SQL Server Express there is no SQL Server Agent, and Database Mail is not a supported feature of that edition. The usual workaround is Windows Task Scheduler with sqlcmd and PowerShell, covered in the Express guide.
On Azure SQL Database there is neither Database Mail nor SQL Server Agent. Azure SQL Managed Instance has both. The options for the single database flavour are in the Azure SQL Database guide.
One or two Database Mail jobs are fine. The trouble starts at ten, when the queries live inside job steps that only a sysadmin can read, the recipients are hardcoded in T-SQL, and nobody can say which report went out this morning.
That is the point where a scheduled SQL export tool is cheaper than another job. In Taavik the query sits in a shared library where the team can read and version it, the schedule runs through an agent inside the network, and the output is a real CSV or Excel file with proper quoting and a header row. Delivery goes to an email list or a Slack channel, with a record of every run. The file is encrypted before it leaves the network and reaches recipients as a download link opened with a passphrase, which is different from an attachment and deliberate: an extract with customer data does not end up sitting in every mailbox it was forwarded to.
It also works the same way on Express, on Azure SQL Database and on a full Enterprise instance, which matters when the estate has all three.