This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to save MailMessage object to disk as *.eml or *.msg file
I am working on a C# program that emails people when certain conditions are met. I want to be able to save a copy of the email for record keeping and can't figure it out. I find it surprising there is just not a built it function like message.Save().
I have included a very basic email sample below:
MailMessage message = new MailMessage("from_email", "to_email");
message.Subject = "Email Alert";
message.Body = "This is a test email.";
SmtpClient Smtp = new SmtpClient("smtp server");
Smtp.Send(message);
I would like to save a copy of the email for a record. I didn't really consider all the choices of ways to store the message, sorry for that. I would like to have copy in case the recipient didn't receive the email I could forward them a copy from archive. I think a .msg would work well.
Another addition, I would like to be able to save the email and then send a batch at the end of the day. In case I receive updates that needed to be added I could have to program add new entries to the email so that recipient wouldn't be overloaded with multiple emails. However, there would be some cases where their would be escalation level when met an email would automatically be sent regardless of the time of day.
Why not BCC the email to an admin account?
Well, you weren't too specific about what you were looking for, so here are a few options:
BCC yourself. This will (privately) send yourself a copy of the email.
Implement a save yourself if you want to save to file. It's not that hard. Really all you want to do is save a few bits of text. We could implement it like this:
private void SaveEmailToDisk(MailMessage message, string saveTo)
{
var builder = new StringBuilder();
builder.AppendFormat("To: {0}\n", String.Join("; ", message.To.Select(m => m.Address).ToArray()));
builder.AppendFormat("From: {0}\n",message.From.Address);
builder.AppendFormat("Subject: {0}", message.Subject);
builder.AppendFormat("Body: {0}", message.Body);
File.WriteAllText(saveTo, builder.ToString());
}
Of course you can tweak it to whatever needs you have.
A couple of different ways to "back up" your email messages so they could be resent if necessary:
ProcMail. Depending on the MTA you're using, it would be easy enough to write a ProcMail recipe to archive messages as your MTA sends them. If you're using Exchange, the same can be done on the server side of things.
XML Serialization. After you create each instance of the MailMessage class, serialize it and store it, either in the file system, or in a database. Should be easy enough to rehydrate instance when needed.
Pickup Directory. The SmtpClient class can be configured to "send" messages to a "Pickup Directory." This is normally used in a configuration where the MTA (message transport agent) is configured to watch a particular directory. Sending mail then consists of dropping a file containing an RFC 2822-compliant message into the directory, where it will shortly get collected by the MTA and sent on its way. If no MTA is configured to watch the pickup directory, the mail message will just get dropped there and sit.
This is a useful way of testing the app that does the mailing without involving a real MTA. People tend to get grumpy when they get slammed with junk messages.
It's also a useful technique for archiving: Configure 2 SmtpClient instances in your program: one configured to talk to your MTA and the other configured to drop the message in a pickup directory. Post each MailMessage you create to both instances and you'll have your archive.
Any one of these techniques should work for you. If you actually need to re-send the email, XML serialization might be the best option for you, as rehydrating an object instance is pretty trivial to do via XML serialization.
The important question to ask here is: Save it to where?
That's why there is not a built-in Save() method. Emails are not typically something that is easily just saved to a file-system (that's not to say they cannot be). But there is a lot of information that is not simply stored, like the To/From address, the Subject line, different parts (ie. MIME alternate parts, attachments).
Use
MailAddress bcc = new MailAddress("youremail#domain.com");
message.Bcc.Add(bcc);
You'll get a copy of the message.
Why not write the data to a database table before sending the email? Then, you have a log of what email was sent.
Related
I looked on SO an found several ways to do kind simmilar things, but those aren't the solution.
A user is on the web page and on a click on a file (which is stored in byte[] on server) should open the mail client, where the attachment, subject and mailfrom is set.
Subject and Mail From is no problem, but the attachment. Here are some points I need/need not to:
I cannot/I am not allowed to Create a file such as mymailmessage.eml
on a client (access denied)
I cannot use MailMessage
(System.Net.Mail) because for this I need to create a file to open the mail client with Process.Start(filename)
I cannot use mailto: because there I cannot add an attachment
So the way I am on for now is to use MAPI. Unfortunately I have not found a solution. My source is a byte[] and I can write this in a MemoryStream. Is it possible to create a kind of virtual file path in C#? But I don't know how to open the mail client including the parameters. All the MAPI projects (like https://github.com/PandaWood/Simple-MAPI.NET or https://www.codeproject.com/Articles/10881/MAPIEx-Extended-MAPI-Wrapper are using local files. I tried those, but in my case the mail client isn't starting, so no mail message window is popping up.
So what I am looking for is: Create a MapiMessage with MailFrom, Subject, an attachment and then open the mail client (like with mailto) including the attachment.
An other C# project is this: https://www.codeproject.com/Articles/17561/Programmatically-adding-attachments-to-emails-in-C
According to this codeproject, I cannot find the line, where the programm is saying the mail client please open (like Process.Start()) and open the prepared mail message for me.
Is there any other way except MAPI, when I only have a byte[] in the web application and need to open a mail client message including the attachment not storing/downloading it on the user client?
I send mails from C# code via Lotus Notes and it works really fine - with Win7 and WinXP.
But some users of my program have multiple .nsf files in the directory, like 'user1.nsf' and 'old-user1.nsf'.
How can I retieve which of these files is the active database I have to use?
If your code runs on users machine then you have "MailFile" and "MailServer" variables in notes.ini file.
Where is this directory located?
You don't need to care which mail database is active if you are sending emails. Just create a new NotesDocument object in memory, fill out the appropriate properties (subject, Body, etc), and then call the Send method on that object. Notes takes care of the rest.
If you need to get the mail database information for a user for another reason, there is a GetUserInfo method for that on the NotesRegistration class
Or in formulas, there is the #MailDbName formula.
If you're just using the user's mail file, in LotusScript you can just use
Call notesDatabase.OpenMail
That way, you never need to bother with where the mail file is - you get the handle to it seemlessly.
I want to fetch emails from an exchange server via more than one windows service; each windows service on separate servers. I am leaning towards using third party tools to fetch emails.
I am concerned about concurrency issues; ie: two services grabbing the same email at the same moment. I DO NOT want to use a controller process that will control which process gets which email.
I am thinking of a locking mechanism, similar to database locks, that each process can lock the email while in process and then mark it, once done. OR
A 'fetch' method that will mark the email instantaneously. in micro micro seconds or even less before any other process gets to it. OR
Any other idea that comes to mind.
Much Obliged
You will probably have to use DB with locking some table. Have your service to populate the table with ToDos and then mark them as completed. Your services will need to point to one place where they will get a work Todo, so this is going to be your concurrency solution. May be, one service just to populate TODOs and others to process them. May be MSMQ can help. One service stacking the queue, others un-stocking.
here is something that you may want to look at
.NET POP3 MIME Client
you may want to try something like this in code as an example as well
Outlook.Application outlook = new Outlook.ApplicationClass();
Outlook.NameSpace ns = outlook.GetNamespace("Mapi");
object _missing = Type.Missing;
ns.Logon(_missing, _missing, false, true);
Outlook.MAPIFolder inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
int unread = inbox.UnReadItemCount;
foreach (Outlook.MailItem mail in inbox.Items)
{
string s = mail.Subject;
}
I'm pulling up the Global Address List from Outlook like so...
Microsoft.Office.Interop.Outlook.Application oApp = new Microsoft.Office.Interop.Outlook.Application();
AddressList gal = oApp.Session.GetGlobalAddressList();
...with the aim of eventually being able to search through this in my own application to retrieve contact information which I can then supply to a method that squirrels off an email. Unfortunately given that my own GAL has about 20K entries in (the customers much more) using a foreach or something simply doesn't work in an acceptable timeframe.
I want to pass a string like "Tom" to a method and have it return a list of possible contacts. Is this possible outside of actually opening up Outlook and creating the mail there?
Note: There are a couple of other questions similar to this but most seem to have no good answer. I'm hoping I have more luck.
Ok, after a LOT of Googling and stress I still haven't come up with a good way to do this. My work around is to search the local contacts folder of a user using this MSDN example. The local contacts folder of any of my users is generally well under a thousand (actually normally well under a hundred) and so there is no real overhead to searching it.
If the users local directory turns up nothing (or they try and send an email to an invalid address using my apps email functionality) then I get Outlook to provide me with with a non-modal "new email" window which has all the body, attachments, title and so on built for me, and the user can use Outlooks search functionality to find the address from the GAL.
Sort of like this...
if(CantFindAddressesLocally)
{
MailItem email = (MailItem)(oApp.CreateItem(OlItemType.olMailItem));
email.Subject = "MY SUBJECT";
email.Body = "MY BODY";
email.Attachments.Add(myAttachment);
email.Display(false) //popup an Outlook "New Email" window
}
Admittedly clumsy since it requires using the Outlook interface (and avoiding that was the whole point of incorporating email functionality in the first place) but at least it generates an email - the only thing left to the user is to input an address that is actually valid.
I am creating eml's and saving them to a directory using procedure mentioned over here.
I want to know how to send these eml files?
I tried using SMTPClient class's object but it takes MailMessage object as its parameter and I couldn't find and way to create an object of type MailMessage using these saved eml files.
Loading an EML file correctly is not as easy as it looks. You can write an implementation working in 95% cases within few days. Remaining 5% would take at least several months ;-). I know, becase I involved in developing one.
Consider following dificulities:
unicode emails
right-to-left languages
correcting malformed EML files caused by well known errors in popular mail clients and servers
dealing with S/MIME (encrypted and signed email messages)
dealing correctly with several methods of encoding attachments
dealing with inline images and stylesheets embedded into HTML emails
making sure that it parses correctly a MIME torture message from Mike Crispin (coauthor of Mime and IMAP RFCs)
making sure that malformed message will not result in buffer overun or other application crash
handling hierarchical messages (message with attached messages)
making sure that it handles correctly very big emails
Maturing of such parser takes years and continuous feedback for it's users. Right now is no such parser included in the .NET Framework. Until it changes I would sugest getting a thrid party MIME parser from an established vendor.
Following code uses our Rebex Secure Mail component, but I'm sure that similar task could be replicated easily with components from other vendors as well.
The code is based on Mail Message tutorial.
// create an instance of MailMessage
MailMessage message = new MailMessage();
// load the message from a local disk file
message.Load("c:\\message.eml");
// send message
Smtp.Send(message, "smtp.example.org");
Use EMLReader to retrieve data from .eml file. It contains all the data you need to create a MailMessage object like From, To, Subject, Body & a whole lot more.
FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite);
EMLReader reader = new EMLReader(fs);
fs.Close();
MailMessage message = new System.Net.Mail.MailMessage(reader.From, reader.To, reader.Subject, reader.Body);
If you're a Microsoft shop and have an Exchange server anyway, then there's another solution which is much, much easier than everything else suggested here:
Each Exchange server has a pickup directory configured out of the box.
By default, it's %ExchangeInstallPath%TransportRoles\Pickup.
You just copy the .eml files to that directory, and Exchange automatically will send the mails.
Read this TechNet article for more information:
Pickup directory and Replay directory
As others demonstrated, EML is just not a good way to serialize a mail message. You might be better off by saving your mails in another format. While there are several serialization engines in the .Net framework to serialize any object, you might also consider just saving the components of your mails, like addresses, body, files to be attached in base64, in an Xml file of your own design.
Below is an example to get you started:
<?xml version="1.0" encoding="utf-8"?>
<mail>
<to display="Thomas Edison" address="tedison#domain.com" />
<body>
Hi Thomas,
How are you doing?
Bye
</body>
<attachment name="MaryLamb.wav">
cmF0aWUgYWFuIGluIFBERi1mb3JtYWF0LiBEZSBmYWN0dXVyIGlzIGVlbiBvZmZpY2ll
ZWwgZ2VzaWduZWVyZA0KZG9jdW1lbnQgdmFuIEV1cm9maW5zIE9tZWdhbSBCVi4gRGUg
c2lnbmF0dXJlIGt1bnQgdSB2ZXJpZmnDq3Jlbi4NCg0KVm9vciBoZXQgdmVyaWZpw6ty
...
</attachment>
</mail>
Added advantage would be that, unlike with creating EML, you do not need the smtpClient to build the concept mail files.
Xml is extremely easy to create and parse in C#.
You did not tell the rationale of saving EML's. If long term archival would be a goal, xml might have an advantage.
Do What i did ... give up.
Building the MailMessage object seems to be the focus i have a similar questions outstanding on here too ...
How do i send an email when i already have it as a string?
From what i've seen the simplest way to do this is to use a raw socket to dump the entire .eml file contents up to the mail server as is and let the mail server figure out the hard stuff like from, to subject, ect by parsing the email using it's engine.
The only problem ... RFC 821 ... such a pain, i'm trying to figure out a clean way to do this and read mail already in the mailbox quickly too.
EDIT:
I found a clean solution and covered it in my thread :)
How do i send an email when i already have it as a string?
You can do this with Windows Server’s built-in SMTP server, the same way as in the previous answer using Exchange.
Drop the .eml file to C:\inetpub\mailroot\Pickup and the raw message will be sent (local or remote).
You can forward messages by simply inserting a line in the top:
To: email#address.com
You can manipulate the mail header further if you require.
For the records:
In Nuget Packager Console write:
Install-Package LumiSoft.Net.dll
Then in your Code:
using (FileStream fs = new FileStream( cacheFileName, FileMode.Open, FileAccess.Read ))
using (LumiSoft.Net.SMTP.Client.SMTP_Client client =
new LumiSoft.Net.SMTP.Client.SMTP_Client())
{
client.SendMessage( fs );
}