> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sequentum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Export script

> Run custom JavaScript, C#, or Python code to customize how an Agent exports extracted data.

The Export Script command executes custom scripts that customize the export process, such as exporting extracted data to custom database structures or other data sources. You can choose a supported programming language for each script. Located under **Export** in the command palette.

## Script properties

**Language:** Select one of the programming languages supported by Sequentum Cloud:

* JavaScript (default)
* C#
* Python

#### C# example script

This script monitors sentiment in news articles, formats the results into an email, and sends an alert when it detects negative sentiment.

```csharp theme={null}
#r System.Data.Common.dll
#r System.Data.dll
#r System.Net.dll
#r System.Net.Mail.dll
#r System.ComponentModel.TypeConverter.dll
#r System.Net.Primitives.dll
#r System.Runtime.InteropServices.dll


using System;
using System.IO;
using System.Data;
using System.Text;
using System.Net;
using System.Net.Mail;
using System.Collections.Generic;


public static bool  ExportScript(ExportContext context)
	{
		var ChatGPT= context.GlobalData["ChatGPT"] as string;
		if(ChatGPT == "1")
		{
			context.Log("Executing Email script");
			var data_files = new List<string>();
			data_files = context.ExportFiles.GetDataFiles();
			var filename= data_files[0];
			var EXPORT_DIR= Path.GetDirectoryName(filename);
			var processedFileName = Path.Combine(EXPORT_DIR, "processed_articles.csv");
			//context.Log("ProcessedFile "+processedFileName);
			if (File.Exists(processedFileName) && (new FileInfo(processedFileName).Length!= 0))
			{
				context.Log("DataTable is not empty");
				var emailBody = generateEmailBody(context, processedFileName);
				//context.Log("emailBody"+emailBody.ToString());
				var dtemail = DateTime.UtcNow.ToString("MM-dd-yyyy");
				string subject = "V4 NewsMonitorBing- Negative Sentiment Alert:" + dtemail;
				sent_email(context, subject, emailBody);
			}
			else
			{
				context.Log("DataTable is empty");
				return true;
			}
		}

		return true;
	}

	public static void sent_email(ExportContext context, string emailSubject, string emailBody)
	{
		if (!string.IsNullOrEmpty(emailBody))
		{
			var toAddress = context.GlobalData["DistributionList"] as string;
			context.Log(toAddress);

			var dtemail = DateTime.UtcNow.ToString("MM-dd-yyyy");

			context.Log("Successful Credentials");

			string img1=context.SharedFiles["NewsMonitor.zip/1c195a45eb5b931303b1766dc9854dbf.png"];
			string img2=context.SharedFiles["NewsMonitor.zip/81d966296b73f2aeecc892b90a47710b.jpg"];
			string img3=context.SharedFiles["NewsMonitor.zip/465665d51ef28198d2939afe39b25604.png"];
			string img4=context.SharedFiles["NewsMonitor.zip/8368706fdbd631efccf7eb83699d3214.png"];
			string[] imagesList = {img1, img2, img3, img4};

			try
			{
				context.ScriptUtilities.SendEmail(toAddress, emailSubject, emailBody, true, null, null, null, imagesList, true, false);
				//smtp.Send(message);
				context.Log("Email sent successfully!");
			}
			catch (Exception ex)
			{
				context.Log("Error sending email: " + ex.Message);
			}
		}
	}

	public static string generateEmailBody(ExportContext context, string csvPath)
	{
		//context.Log("Under generateEmailBody function");
		Dictionary<string, List<Dictionary<string, string>>> negativeNewsArticles = new Dictionary<string, List<Dictionary<string, string>>>();
		List<string> emailMessageList = new List<string>();

		var articleOpeningTag = @"<div class=""w  pr-16 pl-16"" style=""background:#fffffe;background-color:#fffffe;margin:0px auto;max-width:622px;"">
								<table align=""center"" border=""0"" cellpadding=""0"" cellspacing=""0"" role=""presentation"" style=""background:#fffffe;background-color:#fffffe;width:100%;"">
								<tbody><tr><td style=""border:none;direction:ltr;font-size:0;padding:0px 32px 32px 32px;text-align:center;"">";

		var articleClosingTag = "</td></tr></tbody></table></div>";

		var emailTemplate = File.ReadAllText(context.SharedFiles["NewsMonitor.zip/emailTemplate.html"]);
		var insertCompany = File.ReadAllText(context.SharedFiles["NewsMonitor.zip/insertCompanyTag.txt"]);
		var insertArticle = File.ReadAllText(context.SharedFiles["NewsMonitor.zip/insertArticleTag.txt"]);
		var insertSeparator = File.ReadAllText(context.SharedFiles["NewsMonitor.zip/insertArticleSeparatorTag.txt"]);
		var currentDate = DateTime.UtcNow.ToString("MM/dd/yy");

		var csv_read_all = context.ScriptUtilities.LoadCsvFileIntoDataTable(csvPath);
		var articleScanned = csv_read_all.Rows.Count;

		DataView dv = new DataView(csv_read_all);
		dv.RowFilter = "TRIM([Sentiment]) = 'negative'";
		dv.Sort = "Company ASC";
		DataTable filtered_data = dv.ToTable(true);

		var negativeArticles = filtered_data.Rows.Count;

		foreach (System.Data.DataRow row in filtered_data.Rows)
		{
			var companyName = row["Company"].ToString();

			if (!negativeNewsArticles.ContainsKey(companyName))
				negativeNewsArticles[companyName] = new List<Dictionary<string, string>>();

			Dictionary<string, string> articleList = new Dictionary<string, string>
			{
				{"Title", row["Title"].ToString()},
				{"Site Name", row["Site Name"].ToString()},
				{"ImageURL", row["ImageURL"].ToString()},
				{"TitleURL", row["Page Url"].ToString()}
			};
			negativeNewsArticles[companyName].Add(articleList);
		}

		foreach (var kvp in negativeNewsArticles)
		{
			List<string> articleMessageList = new List<string>();
			var companyName = insertCompany.Replace("{COMPANY_NAME}", kvp.Key);

			emailMessageList.Add(companyName);

			foreach (var innerDict in kvp.Value)
			{
				var article = insertArticle.Replace("{ARTICLE_TITLE}", innerDict["Title"])
					.Replace("{ARTICLE_SITE_NAME}", innerDict["Site Name"])
					.Replace("{ARTICLE_IMAGE_URL}", innerDict["ImageURL"])
					.Replace("{ARTICLE_TITLE_URL}", innerDict["TitleURL"]);

				articleMessageList.Add(article);
			}
			var articleBody = string.Join(insertSeparator, articleMessageList.ToArray());

			if (!string.IsNullOrEmpty(articleBody))
			{
				emailMessageList.Add(string.Format("{0}{1}{2}", articleOpeningTag, articleBody, articleClosingTag));
			}
		}

		var articleData = string.Join("", emailMessageList.ToArray());
		//context.Log("articleData value=  "+articleData.ToString());
		emailTemplate = emailTemplate.Replace("{CURRENT_DATE}", currentDate).Replace("{NUMBER_OF_NEGATIVE_ARTICLE}", negativeArticles.ToString()).Replace("{ARTICLE_SCANNED}", articleScanned.ToString()).Replace("{ARTICLE_DATA}", articleData);
		//context.Log("emailTemplate value=  "+emailTemplate.ToString());
		return emailTemplate;
	}
```

**Timeout:** Sets how long the Agent waits for a script to finish before proceeding. The default is 10 minutes, which accommodates slower systems and network connections. A shorter timeout can make extraction faster when the script completes reliably within that period.

Available timeout values are 2, 10, and 30 seconds; 1, 10, and 30 minutes; and 1 and 10 hours. Choose a value based on your script and system performance.

## Files

Refer to the **Files** section for more information.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.