I am writing a simple email helper class that will be called by a Windows service. When I test though the email attachment is not sending with the rest of the email.
mailAttachmentFilePath is an ArrayList (just for clarification) and mail represents MailMessage class.
if (mailAttachmentFilePath.Count > 0)
{
foreach (string file in mailAttachmentFilePath)
{
Attachment data = new Attachment(file);
mail.Attachments.Add(data);
data.Dispose();
}
}
I am certain I am missing something but, I don't know what it is...
Do the data.Dispose() AFTER you send the email :D.
Remove the data.Dispose(). The attachments are being added by reference so when you call dispose it's actually releasing the attached file. You also don't really need the if statement. Try this:
foreach (string file in mailAttachmentFilePath)
{
Attachment data = new Attachment(file);
mail.Attachments.Add(data);
}
Related
In my application users can upload emails to a file server, these emails should then be stripped of their attachments and converted into a PDF to be saved individually. But I'm having problems correctly removing the attachments from the email.
When I'm converting an email and saving it with its attachments it works perfectly, but when I remove the attachments first and then save it, it somehow corrupts the generated PDF file making it look like this (this is just one of 4 pages generated from a 4 line email). Can anyone explain what I'm doing wrong?
This is my code to remove the attachments from the email:
public static List<(string FileName, Stream Content)> GetEmailAndAttachmentsFromEmail(Stream emailContent)
{
var email = MailMessage.Load(emailContent);
var retval = new List<(string, Stream)>
{
($"{email.Subject}.msg", emailContent)
};
var attachmentsToRemove = new List<Attachment>();
foreach (var attachment in email.Attachments)
{
retval.Add((attachment.Name, attachment.ContentStream));
attachmentsToRemove.Add(attachment);
}
foreach (var attachment in attachmentsToRemove)
{
email.Attachments.Remove(attachment);
}
return retval;
}
I've already tried multiple permutations of this code, but none worked.
Also, I'm following the official Aspose documentation on this subject and I don't see what I'm doing differently/ wrong.
It turns out I did something funky with my streams and I had to save my email without the attachments before returning it, here is my revised code:
public static List<(string FileName, Stream Content)> GetEmailAndAttachmentsFromEmail(Stream emailContent)
{
var email = MailMessage.Load(emailContent);
// I removed the prepending of the email here and moved it to the end
var retval = new List<(string, Stream)>();
var attachmentsToRemove = new List<Attachment>();
foreach (var attachment in email.Attachments)
{
retval.Add((attachment.Name, attachment.ContentStream));
attachmentsToRemove.Add(attachment);
}
foreach (var attachment in attachmentsToRemove)
{
email.Attachments.Remove(attachment);
}
// This part is new
var newEmailContent = new MemoryStream();
email.Save(newEmailContent);
newEmailContent.Seek(0, SeekOrigin.Begin);
retval = retval.Prepend(($"{email.Subject}.msg", newEmailContent)).ToList();
return retval;
}
It now works like a charm
Is it possible to save file attachments in C# through Microsoft Graph API?
I know I can get the properties of the attachment (https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/attachment_get) - can we also save it to a certain location?
Once you have particular Microsoft Graph message, you can e.g. pass it to a method as parameter. Then you need to make another request to get attachments by message Id, iterate through attachments and cast it to FileAttachment to get access to the ContentBytes property and finally save this byte array to the file.
private static async Task SaveAttachments(Message message)
{
var attachments =
await _client.Me.MailFolders.Inbox.Messages[message.Id].Attachments.Request().GetAsync();
foreach (var attachment in attachments.CurrentPage)
{
if (attachment.GetType() == typeof(FileAttachment))
{
var item = (FileAttachment)attachment; // Cast from Attachment
var folder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
var filePath = Path.Combine(folder, item.Name);
System.IO.File.WriteAllBytes(filePath, item.ContentBytes);
}
}
}
When you get the attachment properties, they will contain information about the attachment.
There are three types of attachments.
First, check the attachment type in the properties' #odata.type and handle them correspondingly.
For fileAttachment types, they contain a contentLocation attribute, which is the URI of the attachment contents.
You can download the attachment from the URI.
I have created an application that generates excel files from information in a database. These files are saved on my HDD in a folder.
After that I attach the files and send them via mail. When I generate another batch of files I delete the old files and then create the new ones.
My problem is when I have generated one batch of files and then send them, and I want to generate another batch I cannot delete the one of the old files, because the mailing method is still holding on to one of the excel files.
Here is my code:
public void SendMailedFilesDKLol() {
string[] sentFiles=Directory.GetFiles(some_Folder);
if(sentFiles.Count()>0) {
System.Net.Mail.SmtpClient client=new System.Net.Mail.SmtpClient("ares");
System.Net.Mail.MailMessage msg=new System.Net.Mail.MailMessage();
msg.From=new MailAddress("system#lol.dk");
msg.To.Add(new MailAddress("lmy#lol.dk"));
msg.Subject="IBM PUDO";
msg.Body=
sentFiles.Count()+" attached file(s) has been sent to the customer(s) in question ";
msg.IsBodyHtml=true;
foreach(string file in sentFiles) {
Attachment attachment=new Attachment(file);
msg.Attachments.Add(attachment);
}
client.Send(msg);
}
}
I have tried to dispose the client element but that didn't help.
Can anyone help me with this?
Both System.Net.Mail.MailMessage & System.Net.Mail.SmtpClient are IDisposable classes. You can try the following,
using (System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient("ares"))
{
using (System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage())
{
msg.From = new MailAddress("system#lol.dk");
msg.To.Add(new MailAddress("lmy#lol.dk"));
msg.Subject = "IBM PUDO";
msg.Body = sentFiles.Count() + " attached file(s) has been sent to the customer(s) in question ";
msg.IsBodyHtml = true;
foreach (string file in sentFiles)
{
Attachment attachment = new Attachment(file);
msg.Attachments.Add(attachment);
}
client.Send(msg);
}
}
It sounds like you may not be closing your file stream when generating the excel files or you have them open in excel when trying to email them.
Please can you show your code for generating the excel files.
You need to dispose the Attachment objects.
Example using LINQ:
public void SendMailedFilesDKLol() {
string[] sentFiles=Directory.GetFiles(some_Folder);
if(sentFiles.Count()>0) {
System.Net.Mail.SmtpClient client=new System.Net.Mail.SmtpClient("ares");
System.Net.Mail.MailMessage msg=new System.Net.Mail.MailMessage();
msg.From=new MailAddress("system#lol.dk");
msg.To.Add(new MailAddress("lmy#lol.dk"));
msg.Subject="IBM PUDO";
msg.Body=
sentFiles.Count()+" attached file(s) has been sent to the customer(s) in question ";
msg.IsBodyHtml=true;
var attachments = sentFiles.Select(f => new Attachment(f)).ToList();
attachments.ForEach(a => msg.Attachments.Add(a));
client.Send(msg);
attachments.ForEach(a => a.Dispose());
}
}
I have the following code that basically attaches a file to an email message then after all attachments are attached and email is sent, i try to delete all files, however I get a file in use exception. I believe the error comes in this line
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
I tried using this code but I get an cannot sent email message
using Attachment data = new Attachment(file, MediaTypeNames.Application.Octet)){
//and the rest of the code in here.
}
foreach (KeyValuePair<string, string> kvp in reports) {
browser.GoTo(kvp.Value);
Thread.Sleep(1000);
System.IO.File.Move(#"C:\Reports\bidata.csv", #"C:\Reports\"+kvp.Key.ToString()+".csv");
string file = #"C:\Reports\" + kvp.Key.ToString() + ".csv";
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
// Add time stamp information for the file.
ContentDisposition disposition = data.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(file);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(file);
disposition.ReadDate = System.IO.File.GetLastAccessTime(file);
// Add the file attachment to this e-mail message.
mail.Attachments.Add(data);
}
smtpserver.Send(mail);
string[] files = Directory.GetFiles(#"C:\Reports");
foreach (string files1 in files)
{
File.Delete(files1);
}
In order to delete the files first you will have to dispose the attachment and mail objects and then delete the files
Dispose the smtpclient by putting it in a usings or calling dispose directly. That should free the file resource and allow you to nuke it.
I have a function thats sending messages ( a lot of them) and their attachments.
It basically loops through a directory structure and creates emails from a file structure for example
c:\emails\message01
\attachments
c:\emails\message02
\attachments
The creation of the messages takes place using .net c#, standard stuff.
After all messages are created... I have another function that runs directly afterwards that copies the message folder to another location.
Problem is - files are locked...
Note: I'm not moving the files, just copying them....
Any suggestions on how to copy locked files, using c#?
Update
I have this add attachments method
private void AddAttachments(MailMessage mail)
{
string attachmentDirectoryPath = "c:\messages\message1";
DirectoryInfo attachmentDirectory = new DirectoryInfo(attachmentDirectoryPath);
FileInfo[] attachments = attachmentDirectory.GetFiles();
foreach (FileInfo attachment in attachments)
{
mail.Attachments.Add(new Attachment(attachment.FullName));
}
}
How are you reading the files to create the email message? They should be opened as read-only, with a FileShare set to FileShare.ReadWrite... then they shouldn't be locked. If you are using a FileStream you should also wrap your logic in the using keyword so that the resource is disposed properly.
Update:
I believe disposing the mail message itself will close resources within it and unlock the files:
using (var mail = new MailMessage())
{
AddAttachments(mail);
}
// File copy code should work here
hate answering my own post, but yeah for the next poor guy who has this problem here is the fix:
AFTER YOU SEND THE MESSAGE
// Send the mail
client.Send(message);
//Clean up attachments
foreach (Attachment attachment in message.Attachments)
{
attachment.Dispose();
}
Dispose the attachments... clears the lock, and messages will still be sent with attachments. Dispose DOES NOT delete the files, just clears the attachments :)
Are you closing the files after you finish reading them? If you open them for reading, but don't close them when you're done, it should keep a lock on it until the program exits and automatically closes all the files.
MailMessage email = new MailMessage();
email.From = txtFrom.Text;
email.To = txtToEmail.Text;
email.Subject = txtMSubject.Text;
email.Body = txtBody.Text;
SmtpClient mailClient = new SmtpClient();
mailClient.Host = "smtp.emailAddress";
mailClient.Port = 2525;
mailClient.Send(email );
email.Dispose();
// After Disposing the email object you can call file delete
if (filePath != "")
{
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
}
I see this a lot when sending attachments. I normally use something like the following:
In the code that moves the files to a different location, you can use the following pattern:
Inside the loop for looping through the files
bool FileOk = false;
while (!FileOk)
{
try
{
// code to move the file
FileOk = true;
}
catch(Exception)
{
// do nothing or write some code to pause the thread for a few seconds.
}
}