So I know how to send emails with attachments... thats easy.
The problem now is I need to add an MailMessage, that has an attachment of its own, to a different MailMessage. This will allow the user to review things and take the email that is pre-made and send it if everything is ok.
I am not sure this will be the final work flow, but I would like to know if easy.
I see a bunch of software out there that is for money, the users getting these emails will be using an outlook client.
This would be deployed to a cheap shared hosting solutions, must be able to run in Meduim Trust!
I would prefer not to have to lic a 3rd party software, No $ :(
Any ideas would be awesome.
MailMessages cannot be attached to other MailMessages. What you will do is create an .msg file, which is basically a file that stores an e-mail and all of its attachments, and attach that to your actual MailMessage. MSG files are supported by Outlook.
For more information about the file extension, go here: http://www.fileformat.info/format/outlookmsg/
As Justin said, there is no facility to attach one MailMessage to another in the API. I worked around this using the SmtpClient to "deliver" my inner message to a directory, and then attached the resulting file to my outer message. This solution isn't terribly appealing, as it has to make use of the file system, but it does get the job done. It would be much cleaner if SmtpDeliveryMethod had a Stream option.
One thing to note, the SmtpClient adds X-Sender/X-Receiver headers for the SMTP envelope information when creating the message file. If this is an issue, you will have to strip them off the top of the message file before attaching it.
// message to be attached
MailMessage attachedMessage = new MailMessage("bob#example.com"
, "carol#example.com", "Attached Message Subject"
, "Attached Message Body");
// message to send
MailMessage sendingMessage = new MailMessage();
sendingMessage.From = new MailAddress("ted#example.com", "Ted");
sendingMessage.To.Add(new MailAddress("alice#example.com", "Alice"));
sendingMessage.Subject = "Attached Message: " + attachedMessage.Subject;
sendingMessage.Body = "This message has a message attached.";
// find a temporary directory path that doesn't exist
string tempDirPath = null;
do {
tempDirPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
} while(Directory.Exists(tempDirPath));
// create temp dir
DirectoryInfo tempDir = Directory.CreateDirectory(tempDirPath);
// use an SmptClient to deliver the message to the temp dir
using(SmtpClient attachmentClient = new SmtpClient("localhost")) {
attachmentClient.DeliveryMethod
= SmtpDeliveryMethod.SpecifiedPickupDirectory;
attachmentClient.PickupDirectoryLocation = tempDirPath;
attachmentClient.Send(attachedMessage);
}
tempDir.Refresh();
// load the created file into a stream
FileInfo mailFile = tempDir.GetFiles().Single();
using(FileStream mailStream = mailFile.OpenRead()) {
// create/add an attachment from the stream
sendingMessage.Attachments.Add(new Attachment(mailStream
, Regex.Replace(attachedMessage.Subject
, "[^a-zA-Z0-9 _.-]+", "") + ".eml"
, "message/rfc822"));
// send the message
using(SmtpClient smtp = new SmtpClient("smtp.example.com")) {
smtp.Send(sendingMessage);
}
mailStream.Close();
}
// clean up temp
mailFile.Delete();
tempDir.Delete();
Related
I'm using iText to create a PDF from a PDF template which is then emailed. The code is to be executed repeatedly. The created temporary file can't be deleted or overwritten. The error message is "The process cannot access the file 'Tmp.pdf' because it is being used by another process."
string path = Server.MapPath("files");
string tmp = path + #"\Tmp.pdf";
PdfDocument pdfDoc = new PdfDocument(new PdfReader(path + #"\Template.pdf"), new PdfWriter(tmp));
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdfDoc, true);
form.GetField("Content").SetValue(tmpItems.Text);
form.FlattenFields();
pdfDoc.Close();
// Email PDF
MailMessage mailMsg = new MailMessage();
Attachment data = new Attachment(tmp, MediaTypeNames.Application.Octet);
// Add time stamp information for the file.
ContentDisposition disposition = data.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(tmp);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(tmp);
disposition.ReadDate = System.IO.File.GetLastAccessTime(tmp);
mailMsg.Attachments.Add(data);
File.Delete(tmp);
I assumed the file had been closed (pdfDoc.Close();) releasing the resource. The second time the code snippet is used (to create another version to be emailed) to overwrite the file, the error occurs at line 3. As a potential fix, I tried to delete the file but again the error occurs at the deletion point.
This is a very short snippet of code. What is the other process holding on to the file? What am I doing wrong?
I created an email in ASP.NET and I want to add a link to the body, but this not a normal url, its a file that is created via byte array and now I want that file to be linkable in my email, but no matter what I do the link is clickable but nothing opens, here is my code:
FileContentResult eventPass = new FileContentResult(generatedPass, "application/vnd.apple.pkpass");
eventPass.FileDownloadName = "preview.pkpass";
message += "<a href='//" + eventPass + "' target='_blank'>Click Here</a>";
AlternateView alternateView = AlternateView.CreateAlternateViewFromString(message, null, MediaTypeNames.Text.Html);
alternateView.LinkedResources.Add(inline);
email.AlternateViews.Add(alternateView);
email.IsBodyHtml = true;
email.Headers.Add("Content-Type", "application/vnd.apple.pkpass");
I know the file is generated correctly because if I return eventPass the file downloads.
Do I need to save eventPass to the server?
Possible answer here:
How to set mime type of application/vnd.apple.pkpass in order to share pass by link or email
Please mark my answer as correct if this has helped you.
My .NET 4.5 web application uses class SmtpClient to create and send e-mail messages to various recipients.
Each e-mail message consists of:
an HTML message body
an embedded inline image (JPeg or PNG or GIF)
an attachment (PDF)
Sample code is below. It works fine, but there is one gripe from OSX users. Apple's standard mail app renders the image twice; once inlined in the message body, and again following the message body, next to the preview of the PDF attachment.
I tinkered with the following properties; none of which would help.
SmtpClient's DeliveryFormat
MailMessage's IsBodyHtml and BodyTransferEncoding
Attachment's MimeType, Inline, DispositionType, ContentId, FileName, Size, CreationDate, ModificationDate
If I compose a similar e-mail message in MS Outlook and send it off to the Apple user, the image is rendered once, inlined in the message body; exactly as I would like it to be. So apparently it is possible.
After reading this, I inspected the raw MIME data, and noticed Outlook uses multipart/related to group together the message body and the images.
My question:
How do I mimic Outlook's behavior with the classes found in System.Net.Mail?
Things I would rather not do:
Employ external images instead of embedded ones (many e-mail clients initially block these to protect recipient's privacy).
Use third party libraries (to avoid legal hassle). The SmtpDirect class I found here seems to solve the problem (though I got a server exception in return), but it is hard for me to accept a complete rewrite of MS's SmtpClient implementation is necessary for such a subtle change.
Send the e-mail message to a pickup folder, manipulate the resulting .eml file, push the file to our Exchange server.
Minimal code to reproduce the problem:
using System.IO;
using System.Net.Mail;
using System.Net.Mime;
namespace SendMail
{
class Program
{
const string body = "Body text <img src=\"cid:ampersand.gif\" /> image.";
static Attachment CreateGif()
{
var att = new Attachment(new MemoryStream(Resource1.ampersand), "ampersand.gif")
{
ContentId = "ampersand.gif",
ContentType = new ContentType(MediaTypeNames.Image.Gif)
};
att.ContentDisposition.Inline = true;
return att;
}
static Attachment CreatePdf()
{
var att = new Attachment(new MemoryStream(Resource1.Hello), "Hello.pdf")
{
ContentId = "Hello.pdf",
ContentType = new ContentType(MediaTypeNames.Application.Pdf)
};
att.ContentDisposition.Inline = false;
return att;
}
static MailMessage CreateMessage()
{
var msg = new MailMessage(Resource1.from, Resource1.to, "The subject", body)
{
IsBodyHtml = true
};
msg.Attachments.Add(CreateGif());
msg.Attachments.Add(CreatePdf());
return msg;
}
static void Main(string[] args)
{
new SmtpClient(Resource1.host).Send(CreateMessage());
}
}
}
To actually build and run it, you will need an additional resource file Resource1.resx with the two attachments (ampersand and Hello) and three strings host (the SMTP server), from and to (both of which are e-mail addresses).
(I found this solution myself before I got to posting the question, but decided to publish anyway; it may help out others. I am still open for alternative solutions!)
I managed to get the desired effect by using class AlternateView.
static MailMessage CreateMessage()
{
var client = new SmtpClient(Resource1.host);
var msg = new MailMessage(Resource1.from, Resource1.to, "The subject", "Alternative message body in plain text.");
var view = AlternateView.CreateAlternateViewFromString(body, System.Text.Encoding.UTF8, MediaTypeNames.Text.Html);
var res = new LinkedResource(new MemoryStream(Resource1.ampersand), new ContentType(MediaTypeNames.Image.Gif))
{
ContentId = "ampersand.gif"
};
view.LinkedResources.Add(res);
msg.AlternateViews.Add(view);
msg.Attachments.Add(CreatePdf());
return msg;
}
As a side effect, the message now also contains a plain text version of the body (for paranoid web clients that reject HTML). Though it is a bit of a burden ("Alternative message body in plain text" needs improvement), it does give you more control as to how the message is rendered under different security settings.
I have excel file abc.xls and I renamed it as abc.doc using command prompt.
My requirement is: I want to upload a proper doc file, but there I can only check the MIME type of the file to upload file, this is not sufficient. I want to confirm before uploading the doc file, that it is a doc and not allow users to upload abc.doc file, because it is not a doc file its a excel file.
Because the OP wrote it in the comments:
You are on a wrong track here, Validation should always happen on the server side, you can add additional validation on the client side, but its not required. You have to do this for a simple reason:
Clients can always circumvent client-side Validation methods because the Client is fully under their control. So even if you implement your validation method to check if its a doc or excel document, a bad user can always just send you a post request with the validation disabled and you're getting a excel document or a virus etc.
This is a core webprogramming principle: Never trust input data, you can't validate on the client only!
Secondly your validation is done much mor easily on the server. So you should upload any file (check for file extensions & size) and then validate on the server!
You probably need an ActiveX Object to access the file content on the client system before uploading. Checking the byte array with javascript to find whether it's a real doc might prove interesting though :-)
EDIT :
function CheckWordDoc(filepath){
var fso, f, ts, s;
var ForReading = 1, ForWriting = 2, ForAppending = 8;
var TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0;
fso = new ActiveXObject("Scripting.FileSystemObject");
f = fso.getFile(filepath);
ts = f.OpenAsTextStream(ForReading, TristateUseDefault);
while (!ts.AtEndOfStream) {
s = ts.ReadLine();
if (s.indexOf("Word.Document.8") != -1) {
ts.Close( );
return true;
}
}
ts.Close( );
return false;
}
http://www.piclist.com/techref/language/asp/vbs/vbscript/jsmthopenastextstream.htm
http://msdn.microsoft.com/en-us/library/hwfw5c59%28v=vs.85%29.aspx
My ASP.NET MVC application will take a lot of bandwidth and storage space. How can I setup an ASP.NET upload page so the file the user uploaded will go straight to Amazon S3 without using my web server's storage and bandwidth?
Update Feb 2016:
The AWS SDK can handle a lot more of this now. Check out how to build the form, and how to build the signature. That should prevent you from needing the bandwidth on your end, assuming you need to do no processing of the content yourself before sending it to S3.
If you need to upload large files and display a progress bar you should consider the flajaxian component.
It uses flash to upload files directly to amazon s3, saving your bandwidth.
The best and the easiest way to upload files to amazon S3 via asp.net . Have a look at following blog post by me . i think this one will help. Here i have explained from adding a S3 bucket to creating the API Key, Installing Amazon SDK and writing code to upload files. Following are are the sample code for uploading files to amazon S3 with asp.net C#.
using System
using System.Collections.Generic
using System.Linq
using System.Web
using Amazon
using Amazon.S3
using Amazon.S3.Transfer
///
/// Summary description for AmazonUploader
///
public class AmazonUploader
{
public bool sendMyFileToS3(System.IO.Stream localFilePath, string bucketName, string subDirectoryInBucket, string fileNameInS3)
{
// input explained :
// localFilePath = we will use a file stream , instead of path
// bucketName : the name of the bucket in S3 ,the bucket should be already created
// subDirectoryInBucket : if this string is not empty the file will be uploaded to
// a subdirectory with this name
// fileNameInS3 = the file name in the S3
// create an instance of IAmazonS3 class ,in my case i choose RegionEndpoint.EUWest1
// you can change that to APNortheast1 , APSoutheast1 , APSoutheast2 , CNNorth1
// SAEast1 , USEast1 , USGovCloudWest1 , USWest1 , USWest2 . this choice will not
// store your file in a different cloud storage but (i think) it differ in performance
// depending on your location
IAmazonS3 client = new AmazonS3Client("Your Access Key", "Your Secrete Key", Amazon.RegionEndpoint.USWest2);
// create a TransferUtility instance passing it the IAmazonS3 created in the first step
TransferUtility utility = new TransferUtility(client);
// making a TransferUtilityUploadRequest instance
TransferUtilityUploadRequest request = new TransferUtilityUploadRequest();
if (subDirectoryInBucket == "" || subDirectoryInBucket == null)
{
request.BucketName = bucketName; //no subdirectory just bucket name
}
else
{ // subdirectory and bucket name
request.BucketName = bucketName + #"/" + subDirectoryInBucket;
}
request.Key = fileNameInS3 ; //file name up in S3
//request.FilePath = localFilePath; //local file name
request.InputStream = localFilePath;
request.CannedACL = S3CannedACL.PublicReadWrite;
utility.Upload(request); //commensing the transfer
return true; //indicate that the file was sent
}
}
Here you can use the function sendMyFileToS3 to upload file stream to amazon S3.
For more details check my blog in the following link.
Upload File to Amazon S3 via asp.net
I hope the above mentioned link will help.
Look for a javascript library to handle the client side upload of these files. I stumbled upon a javascript and php example Dojo also seems to offer a clientside s3 file upload.
ThreeSharp is a library to facilitate interactions with Amazon S3 in a .NET environment.
You'll still need to host the logic to upload and send files to s3 in your mvc app, but you won't need to persist them on your server.
Save and GET data in aws s3 bucket in asp.net mvc :-
To save plain text data at amazon s3 bucket.
1.First you need a bucket created on aws than
2.You need your aws credentials like
a)aws key b) aws secretkey c) region
// code to save data at aws
// Note you can get access denied error. to remove this please check AWS account and give //read and write rights
Name space need to add from NuGet package
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
var credentials = new Amazon.Runtime.BasicAWSCredentials(awsKey, awsSecretKey);
try`
{
AmazonS3Client client = new AmazonS3Client(credentials, RegionEndpoint.APSouth1);
// simple object put
PutObjectRequest request = new PutObjectRequest()
{
ContentBody = "put your plain text here",
ContentType = "text/plain",
BucketName = "put your bucket name here",
Key = "1"
//put unique key to uniquly idenitify your data
// you can pass here any data with unique id like primary key
//in db
};
PutObjectResponse response = client.PutObject(request);
}
catch(exception ex)
{
//
}
Now go to your AWS account and check the bucket you can get data with "1" Name in the AWS s3 bucket.
Note:- if you get any other issue please ask me a question here will try to resolve it.
To get data from AWS s3 bucket:-
try
{
var credentials = new Amazon.Runtime.BasicAWSCredentials(awsKey, awsSecretKey);
AmazonS3Client client = new AmazonS3Client(credentials, RegionEndpoint.APSouth1);
GetObjectRequest request = new GetObjectRequest()
{
BucketName = bucketName,
Key = "1"// because we pass 1 as unique key while save
//data at the s3 bucket
};
using (GetObjectResponse response = client.GetObject(request))
{
StreamReader reader = new
StreamReader(response.ResponseStream);
vccEncryptedData = reader.ReadToEnd();
}
}
catch (AmazonS3Exception)
{
throw;
}