Retrieving email attachments from server - c#

We have an email coming at regular intervals (the request will be user driven), containing an Excel attachment. The goal is to extract the attachment from the email automatically, and pass it on to the method that will deal with the data in the file.
I'd like to stay away from 3rd party tools or libraries, and I'd like to keep this as simple as possible, minimal checks and features, literally just download the mail, save the attachment, if the email address matches the known source (to block spam).
From researching, there are 3 possible solutions. Which would be the most sensible route? And are there other options? Can anybody point me to relevant (and recent) tutorials?
Download using a 3rd party POP client
Write my own functionality, possibly using Exchange EWS (Preferred option) (using C#, VS2010)
Rather have Outlook download it, and then extract the attachment from Outlook

Here is an example of how I do it with our system. Let me know if you want me to explain anything as I did have to post this pretty quick.
namespace Namespace.Email
{
public class EmailLinker
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
public EmailLinker()
{
service.Credentials = new NetworkCredential("username", "password", "domain");
service.AutodiscoverUrl("email#email.com");
}
public void linkEmails()
{
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, new ItemView(128));
if (findResults.TotalCount > 0)
{
ServiceResponseCollection<GetItemResponse> items = service.BindToItems(findResults.Select(item => item.Id), new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.From, EmailMessageSchema.ToRecipients));
foreach (GetItemResponse i in items)
{
MailItem m = new MailItem();
Item it = i.Item;
m.From = ((Microsoft.Exchange.WebServices.Data.EmailAddress)it[EmailMessageSchema.From]).Address;
m.Recipients = ((Microsoft.Exchange.WebServices.Data.EmailAddressCollection)it[EmailMessageSchema.ToRecipients]).Select(r => r.Address).ToArray();
m.Subject = it.Subject;
m.Body = it.Body.Text;
m.Recieved = it.DateTimeReceived;
m.attachments = it.Attachments;
foreach (Attachment a in m.attachments)
this.uploadAttachments(a);
i.Item.Delete(DeleteMode.HardDelete);
}
}
}
private void uploadAttachments(Attachment a)
{
ContentFile cf = new ContentFile();
cf.Name = a.Name;
cf.Size = a.Size;
cf.ContentType = MimeTypeMap.GetMimeType(Path.GetExtension(a.Name).Replace(".",""));
FileAttachment fa = (FileAttachment)a;
fa.Load();
cf.Data = fa.Content;
cf.DateAdded = DateTime.Now;
cf.save();
}
public class MailItem
{
public int id;
public string From;
public string[] Recipients;
public string Subject;
public string Body;
public DateTime Recieved;
public string RecievedString
{
get
{
return Recieved.ToShortDateString() + " " + Recieved.ToShortTimeString();
}
}
public AttachmentCollection attachments;
}
}
}

public class KCSExchangeLink : IKCSExchangeLink
{
private bool CertificateValidationCallBack(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
// If the certificate is a valid, signed certificate, return true.
if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
// If there are errors in the certificate chain, look at each error to determine the cause.
if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
if (chain != null && chain.ChainStatus != null)
{
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
{
if ((certificate.Subject == certificate.Issuer) &&
(status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
{
// Self-signed certificates with an untrusted root are valid.
continue;
}
else
{
if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
{
// If there are any other errors in the certificate chain, the certificate is invalid,
// so the method returns false.
return false;
}
}
}
}
// When processing reaches this line, the only errors in the certificate chain are
// untrusted root errors for self-signed certificates. These certificates are valid
// for default Exchange server installations, so return true.
return true;
}
else
{
// In all other cases, return false.
return false;
}
}
private bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
public void SaveAttachment(string email, string password, string downloadfolder, string fromaddress)
{
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials(email, password);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.AutodiscoverUrl(email, RedirectionUrlValidationCallback);
// Bind the Inbox folder to the service object.
Folder inbox = Folder.Bind(service, WellKnownFolderName.Inbox);
// The search filter to get unread email.
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
ItemView view = new ItemView(1);
// Fire the query for the unread items.
// This method call results in a FindItem call to EWS.
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, sf, view);
foreach (EmailMessage item in findResults)
{
item.Load();
/* download attachment if any */
if (item.HasAttachments && item.Attachments[0] is FileAttachment && item.From.Address == fromaddress)
{
FileAttachment fileAttachment = item.Attachments[0] as FileAttachment;
/* download attachment to folder */
fileAttachment.Load(downloadfolder + fileAttachment.Name);
}
/* mark email as read */
item.IsRead = true;
item.Update(ConflictResolutionMode.AlwaysOverwrite);
}
}
}

Related

Tracking Microsoft 365 Outlook Email to SQL Server

I want to fetch the details from my outlook mailbox but don't have the Microsoft exchange server. I only have cloud-based services.
I tried to use the below-given code but that is an exchange server API solution. The second method is to open the outlook app and then accessing the mailbox but doesn't want this solution.
try
{
'Mailbox credentials'
string emailAddress = AppSettings.Office365EmailAddress;
string password = AppSettings.Office365Password;
ServicePointManager.ServerCertificateValidationCallback =
CertificateValidationCallBack;
ExchangeService service = new
ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Credentials = new WebCredentials(emailAddress, password);
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
service.PreAuthenticate = true;
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,
emailAddress);
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox,
SetFilter(), view);
DataTable dtEmails = GenerateEmailDataTable();
DataRow dr = dtEmails.NewRow();
foreach (Item item in findResults.Items)
{
if (item.Subject != null)
{
Match match = Regex.Match(item.Subject.ToString(), regJMSNumber);
if (match != null)
{
dr["EmailTo"] = item.DisplayTo.ToString();
dr["EmailFrom"] = item.DisplayTo.ToString();
dr["EmailCC"] = item.DisplayCc.ToString();
dr["EmailBCC"] = item.DisplayTo.ToString();
dr["EmailSubject"] = item.Subject.ToString();
dr["EmailBody"] = item.Body.ToString();
dr["CreatedOn"] = item.Subject.ToString();
dr["IsActive"] = true;
}
else
{
Console.WriteLine("Subject Not Match");
}
}
}
}
'Error handler.'
catch (System.Exception e)
{
Console.WriteLine("{0} Exception caught: ", e);
}
finally
{
}
Another approach is the Power Automate option but I want to do it programmatically.
Used https://outlook.office365.com/EWS/Exchange.asmx API.
When I am using EWS (exchange API), the application throwing a 401 Unauthorised requests failed exception.
Please tell me any other way to track the outlook emails with all details like EmailTo, EmailSent, EmailSubject, EmailBody, EmailCC, EmailBCC, and all the trailing messages.

the request was aborted could not create ssl/tls secure channel on shared hosting server C#

We are not able to connect to https server using webrequest or htmlagilitypack It showing below error
The underlying connection was closed: An unexpected error occurred on a receive.System.Net.WebException: or could not create SSL/TLS secure channel on server
Our code works fine on localhost and we also added following portion in my code file but we aren't able to identify why it's happening only on the server.
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
if anyone has any idea on this then please share with us.
Sometimes it is because the webrequest wont accept self signed certificates. I have this singleton class I usually use. It accepts all self signed certificates. It would be easier to determine if there is a simpler solution if if you shared the url you are trying to access.
public sealed class Certificates
{
private static Certificates instance = null;
private static readonly object padlock = new object();
Certificates()
{
}
public static Certificates Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Certificates();
}
return instance;
}
}
}
public void GetCertificatesAutomatically()
{
ServicePointManager.ServerCertificateValidationCallback +=
new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors)
=> { return true; });
}
private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
//Return true if the server certificate is ok
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
bool acceptCertificate = true;
string msg = "The server could not be validated for the following reason(s):\r\n";
//The server did not present a certificate
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable)
{
msg = msg + "\r\n -The server did not present a certificate.\r\n";
acceptCertificate = false;
}
else
{
//The certificate does not match the server name
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
{
msg = msg + "\r\n -The certificate name does not match the authenticated name.\r\n";
acceptCertificate = false;
}
//There is some other problem with the certificate
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
{
foreach (X509ChainStatus item in chain.ChainStatus)
{
if (item.Status != X509ChainStatusFlags.RevocationStatusUnknown &&
item.Status != X509ChainStatusFlags.OfflineRevocation)
break;
if (item.Status != X509ChainStatusFlags.NoError)
{
msg = msg + "\r\n -" + item.StatusInformation;
acceptCertificate = false;
}
}
}
}
//If Validation failed, present message box
if (acceptCertificate == false)
{
msg = msg + "\r\nDo you wish to override the security check?";
// if (MessageBox.Show(msg, "Security Alert: Server could not be validated",
// MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
acceptCertificate = true;
}
return acceptCertificate;
}
}
Just call the method before doing a web request like so.
Certificates.Instance.GetCertificatesAutomatically();
Also it would help diagnose the problem if we could see(the code) how you're making your webrequest.

C# - Connect to Outlook 2010 Mailbox to take Xls Files

I had a a c# script that connects to an OFFICE 365 mailbox and then take any emails with an xls file and puts it in a shared folder. Problem is now the OFFICE 365 mailbox has becomes an Outlook 2010 on premises mailbox, and the script has stopped working.
My questions is what Service URL and service credentials do I use, Is it the same syntax or do I need a new way of connecting in the script ?
OLD script
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Exchange.WebServices.Data;
namespace ST_0710846949654fbd84606ec3011bd081.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
/*
The execution engine calls this method when the task executes.
To access the object model, use the Dts property. Connections, variables, events,
and logging features are available as members of the Dts property as shown in the following examples.
To reference a variable, call Dts.Variables["MyCaseSensitiveVariableName"].Value;
To post a log entry, call Dts.Log("This is my log text", 999, null);
To fire an event, call Dts.Events.FireInformation(99, "test", "hit the help message", "", 0, true);
To use the connections collection use something like the following:
ConnectionManager cm = Dts.Connections.Add("OLEDB");
cm.ConnectionString = "Data Source=localhost;Initial Catalog=AdventureWorks;Provider=SQLNCLI10;Integrated Security=SSPI;Auto Translate=False;";
Before returning from this method, set the value of Dts.TaskResult to indicate success or failure.
To open Help, press F1.
*/
public void Main()
{
ExchangeService service = new ExchangeService();
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.Credentials = new WebCredentials("xxreturns#xxxxxxxxxxxx.co.uk", "PasswordXXXXXXXXX", "mail.xxxxxxxxxxxxxxx.co.uk");
service.Url = new Uri("https://mail.xxxxxxxxxxx.co.uk/owa");
// Variable population
string FileName1 = null;
string attSaveLocation = Dts.Variables["User::attSaveLocation"].Value.ToString();
string destfold = Dts.Variables["User::destFolder"].Value.ToString();
string emailFrom = Dts.Variables["User::emailFrom"].Value.ToString();
string filetype = Dts.Variables["User::filetype"].Value.ToString();
//find items in the email folder
FindItemsResults<Item> foundItems =
service.FindItems(WellKnownFolderName.Inbox, new ItemView(600)); //can limit how many results are pulled
foreach (Item item in foundItems)
{
string tmpitemid;
string processed = null;
tmpitemid = item.Id.ToString();
if (item is EmailMessage)
{
// Bind to an existing message item, requesting its Id property (using the tmpitemid) plus its attachments collection.
EmailMessage foundEmail = EmailMessage.Bind(service, new ItemId(tmpitemid), new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments));
EmailMessage foundEmail2 = (EmailMessage)item;
FindFoldersResults findResults = service.FindFolders(WellKnownFolderName.Inbox, new FolderView(10));
//get the from e-mail address for exchange addresses
string fromaddress = null;
NameResolutionCollection nd = service.ResolveName(foundEmail2.From.Address);
foreach (NameResolution nm in nd)
{
if (nm.Mailbox.RoutingType == "SMTP")
{
fromaddress = nm.Mailbox.Address.ToLower();
}
else
{
fromaddress = foundEmail2.From.Address.ToString().ToLower();
}
}
//for other addresses
if (fromaddress == null)
{
fromaddress = foundEmail2.From.Address.ToString().ToLower();
}
//if the email address is like the parameter
if (fromaddress.Contains(emailFrom))
{
//process attachments
foreach (Attachment attachment in foundEmail.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
FileName1 = attSaveLocation + fileAttachment.Name;
if (fileAttachment.Name.Contains(filetype))
{
fileAttachment.Load(FileName1);
processed = "Y";
}
}
}
if (processed == "Y")
{
// Get all the folders in the message's root folder.
Folder rootfolder = Folder.Bind(service, WellKnownFolderName.Inbox);
rootfolder.Load();
foreach (Folder folder in rootfolder.FindFolders(new FolderView(100)))
{
if (folder.DisplayName == destfold)
{
foundEmail2.Move(folder.Id);
}
}
}
}
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
}
}
Not sure if this works for Outlook 2010, but perhaps this link can help you:
https://msdn.microsoft.com/en-us/office/office365/api/mail-rest-operations

EWS - Get a custom header

Hello I am using the following code to get the custom header from EWS.
But unfortunately it's not returning the header. I looked into the outlook for the headers using Mapi tool, where I can see the headers.
Any suggestions please.
service = ExchangeServiceHelpers.GetBinding();
// Bind the Inbox folder to the service object
var inbox = Folder.Bind(service, WellKnownFolderName.Inbox);
var searchFilter = ExchangeServiceHelpers.PopulateSearchFilters();
var view = new ItemView(int.MaxValue); // Search operation should return maximum number of elements.
// Defines a property set that contains the schematized Internet message headers.
var headerProperty = new ExtendedPropertyDefinition(
DefaultExtendedPropertySet.InternetHeaders,
"x-worksitefolderemailid",
MapiPropertyType.String);
var columns = new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.InternetMessageId, headerProperty);
view.PropertySet = columns;
// Fire the query for the unread items
var findResults = inbox.FindItems(searchFilter, view);
// Loop through the search results.
foreach (EmailMessage message in findResults)
{
try
{
message.Load(
new PropertySet(new PropertyDefinitionBase[] { ItemSchema.MimeContent, ItemSchema.Subject}));
string mailAddress = GetFolderId(message, headerProperty); // Get internet header
if (string.IsNullOrEmpty(mailAddress))
{
Logger.Info(
string.Format("Email '{0}' doesn't have folder id address. Marking as Read Item.",
message.Subject));
ExchangeServiceHelpers.MarkMessageAsRead(service, message.Id); // Marking the email item as Read prevents the item to be returned in further search results.
continue;
}
}
catch (Exception e)
{
Logger.Error(e);
}
}
private static string GetFolderId(EmailMessage message, ExtendedPropertyDefinition headerProperty)
{
try
{
if (message.ExtendedProperties == null || message.ExtendedProperties.Count == 0)
{
Logger.Info(
string.Format("Email '{0}' doesn't have any extended properties. Marking as Read Item.",
message.Subject));
return string.Empty;
}
//message.InternetMessageHeaders
foreach (ExtendedProperty property in message.ExtendedProperties)
{
if (property.PropertyDefinition == headerProperty)
{
return property.Value.ToString();
}
}
}
catch (Exception ex)
{
Logger.Error(ex);
}
return string.Empty;
}
Naresh,
The inbox.FindItems() call won't return the internet headers. You'll need to update message.Load() to use a property set that includes headerProperty.
With regards,

Querying the Global Address List (GAL) via Exchange Web Services (EWS) erreor SSL

My English is not good but I'll do my best.
I try to access Exchange 2010 via EWS, I want to get the contacts of a mailbox
Reading emails in the inbox works perfectly
Here is my code and thank you in advance for your response
class Program
{
static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback = delegate(Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
// If the certificate is a valid, signed certificate, return true.
if (errors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
// If there are errors in the certificate chain, look at each error to determine the cause.
if ((errors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
if (chain != null && chain.ChainStatus != null)
{
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
{
if ((certificate.Subject == certificate.Issuer) &&
(status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
{
// Self-signed certificates with an untrusted root are valid.
continue;
}
else
{
if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
{
// If there are any other errors in the certificate chain, the certificate is invalid,
// so the method returns false.
return false;
}
}
}
}
// When processing reaches this line, the only errors in the certificate chain are
// untrusted root errors for self-signed certificates. These certificates are valid
// for default Exchange Server installations, so return true.
return true;
}
else
{
// In all other cases, return false.
return false;
}
};
ExchangeService _service = new ExchangeService(ExchangeVersion.Exchange2010);
_service.Credentials = new WebCredentials("user", "password");
_service.Url = new Uri("https://mail.domain.be/ews/exchange.asmx");
//Mail dans mailbox
FindItemsResults<Item> findResults = _service.FindItems(
WellKnownFolderName.Inbox, new ItemView(10));
foreach (Item item in findResults.Items)
Console.WriteLine(item.Subject);
Console.ReadLine();
//CONtact mailbox
foreach (Contact contact in _service.FindItems(WellKnownFolderName.Contacts, new ItemView(int.MaxValue)))
{
Console.WriteLine(contact);
}
}
My solution:
static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback = delegate(Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
if (errors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
if ((errors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
if (chain != null && chain.ChainStatus != null)
{
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
{
if ((certificate.Subject == certificate.Issuer) &&
(status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
{
continue;
}
else
{
if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
{
return false;
}
}
}
}
return true;
}
else
{
return false;
}
};
ExchangeService _service = new ExchangeService(ExchangeVersion.Exchange2010);
_service.Credentials = new WebCredentials("user", "password");
_service.Url = new Uri("https://mail.domain.com/ews/exchange.asmx");
//Contact mailbox
ContactsFolder contactsfolder = ContactsFolder.Bind(_service, WellKnownFolderName.Contacts);
int numItems = contactsfolder.TotalCount < int.MaxValue ? contactsfolder.TotalCount : int.MaxValue;
ItemView view = new ItemView(numItems);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ContactSchema.DisplayName);
FindItemsResults<Item> contactItems = _service.FindItems(WellKnownFolderName.Contacts, view);
foreach (Item item in contactItems)
{
if (item is Contact)
{
Contact contact = item as Contact;
Console.WriteLine(contact.DisplayName);
}
}
Console.ReadLine();
}

Categories

Resources