I wrote a code to make attachments for email sending, but I cannot understand how to make it not only for txt files. I know that all the binary files are broken because of "File.OpenText" in my code. Someone can explain to me, how to make it for all files, not only for txt.
public async Task<ResponseData> SendEmail(VictimData victimData, SmtpData senderData, LetterData letter)
{
ResponseData response = new ResponseData();
BodyBuilder bodyBuilder = new BodyBuilder();
string newAttachment = "";
try
{
MimeMessage message = new MimeMessage();
message.From.Add(new MailboxAddress(senderData.senderName, senderData.senderEmail));
message.To.Add(new MailboxAddress("", victimData.email));
/*message.Bcc.Add(new MailboxAddress(senderData.senderName, senderData.senderEmail));
message.ReplyTo.Add(new MailboxAddress(senderData.senderName, senderData.senderEmail));*/
message.Subject = letter.subject;
if (letter.isHtml)
{
bodyBuilder.HtmlBody = letter.body;
}
else
{
bodyBuilder.TextBody = letter.body;
}
foreach (var attachment in letter.attachment)
{
newAttachment = ReadAndReplaceAttachment(attachment.filePath, victimData.email, attachment.fileName);
bodyBuilder.Attachments.Add(newAttachment);
File.Delete(newAttachment);
Console.WriteLine(newAttachment);
}
message.Body = bodyBuilder.ToMessageBody();
await client.SendAsync(message);
response.status = true;
response.messages = "";
return response;
}
catch (Exception ex)
{
response.messages = ex.Message;
response.status = false;
return response;
}
}
private string ReadAndReplaceAttachment(string filePath, string email, string newFileName)
{
Replacer replacer = new Replacer();
string tempFile = Path.Combine(Helpers.tempPath, replacer.DoReplace(newFileName, email));//Path.GetTempPath() + Guid.NewGuid().ToString() + Path.GetExtension(filePath);
string contentResult = "";
using (StreamReader sr = File.OpenText(filePath))
{
contentResult = sr.ReadToEnd();
contentResult = replacer.DoReplace(contentResult, email);
sr.Close();
}
using (var tw = new StreamWriter(tempFile, true))
{
tw.Write(contentResult);
}
return tempFile;
}
You would need to change your code to only call your ReadAndReplaceAttachment() method for txt files and not for any other type of file. For non-text files, you would just attach the original file referenced by attachment.filePath.
Related
I am uploading a file and wish to name it with one of the input fields which I wille be typing in my view. For ex: I type "Test" in my "Designation Commerciale" field. However, it gives me the NullReferenceException as it does not find any. Would appreciate your help. Thanks.
Controller:
public async Task<string> UploadFile(IFormFile file)
{
//bool iscopied;
string resp = String.Empty;
try
{
if (file.Length > 0)
{
var model = new IdentificationProduitViewModel();
string x = model.DesignationCommerciale;
string filename = x + Path.GetExtension(file.FileName);
string path = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "UploadFds"));
using (var filestream = new FileStream(Path.Combine(path, filename), FileMode.Create))
{
await file.CopyToAsync(filestream);
}
//iscopied = true;
resp = filename;
}
else
{
// iscopied = false;
resp = String.Empty;
}
}
catch(Exception)
{
throw;
}
return resp;
}
HTTPPOST:
string tryupload = await UploadFile(file_fds);
if (!String.IsNullOrEmpty(tryupload))
{
TempData["uploadok"] = "Fichier chargé avec success !";
model.Fds_Filepath = tryupload;
}
I'm trying to send an email with attachment when I access an action of ASP.NET Core controller. The attachment is downloaded by a site that exports an html page to pdf. The function sends the email but it can't delete the attachment file because it is still used by another process.
Where is the mistake?
public void SendAsHtml(string body, string subject, string emailTo, string url = null, string fileName = null)
{
string path = null;
using (SmtpClient client = GetSmtpClient())
{
MailMessage mailMessage = new MailMessage
{
From = new MailAddress(sendemail),
Body = body,
Subject = subject,
IsBodyHtml = true
};
mailMessage.To.Add(emailTo);
if (url != null)
{
if (fileName == null)
{
fileName = DateTime.Now.ToString("yyyyMMddHHmmss.pdf");
}
if (!fileName.EndsWith(".pdf"))
{
fileName += ".pdf";
}
path = #"c:\temp\" + fileName;
DeleteFile(path);
using (WebClient myWebClient = new WebClient())
{
myWebClient.DownloadFile($"{htmlToPdfServer}?url=" + url, path);
}
Attachment attachment = new Attachment(path);
mailMessage.Attachments.Add(attachment);
}
client.Send(mailMessage);
}
if (path != null)
{
// it does not work
DeleteFile(path);
}
}
private static void DeleteFile(string path)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
}
catch (Exception ex)
{
Log.Warning($"Send email service: cannot delete file {path} {ex.Message}");
}
}
You should try calling attachment.Dispose() after sending the mail message.
To do this, declare Attachment attachment; before if (url != null) and call Dispose() after client.Send(mailMessage); if attachment != null.
I am adding attachments to my mail but it is sending empty attachments.
I am looking for a quick solution please answer this.
I am adding attachments to my mail but it is sending empty attachments.
I am looking for a quick solution please answer this.
my API code->
var UserId = User.Identity.GetUserId();
UserId = UserId.ToString();
if (!string.IsNullOrEmpty(UserId))
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var provider = await Request.Content.ReadAsMultipartAsync<MemoryMultipartFormDataStreamProvider>(new MemoryMultipartFormDataStreamProvider());
//access form data
NameValueCollection formData = provider.FormData;
//access files
IList<HttpContent> files = provider.Files;
List<string> fileNames = new List<string>();
List<string> filePaths = new List<string>();
List<Stream> inputs = new List<Stream>();
//HttpContent file1 = files[0];
foreach (HttpContent file1 in files)
{
var thisFileName = file1.Headers.ContentDisposition.FileName.Trim('\"');
fileNames.Add(thisFileName);
string filepath = String.Empty;
Stream input = await file1.ReadAsStreamAsync();
inputs.Add(input);
string directoryName = String.Empty;
string URL = String.Empty;
string tempDocUrl = WebConfigurationManager.AppSettings["DocsUrl"];
if (formData["ClientDocs"] != "ClientDocs")
{
var path = HttpRuntime.AppDomainAppPath;
directoryName = HttpContext.Current.Server.MapPath("~/Documents/");
filepath = System.IO.Path.Combine(directoryName, thisFileName);
filePaths.Add(filepath);
//Deletion exists file
if (File.Exists(filepath))
{
File.Delete(filepath);
}
}
using (var fileStream = new FileStream(filepath, FileMode.Create))
{
await file1.CopyToAsync(fileStream);
}
}
ContactModel contactModel = new ContactModel();
contactModel.FileName = fileNames;
contactModel.FilePath = filePaths;
contactModel.ToEmail = formData["To"];
contactModel.Message = formData["Message"];
contactModel.Subject = formData["Subject"];
contactModel.ContactId = Convert.ToInt64(formData["ContactId"]);
contactModel.ContentStream = inputs;
contactModel.ContactTypeId = 2;//Check Enums->ContactTypeId for more description
bool status = await _ContactService.ContactByEmail(contactModel);
HttpResponses.CreateResponsesMessage(HttpStatusCodeEnum.Ok.ToString("D"), Resource.EmailSent, responseMessage);
}
else
{
responseMessage = HttpResponses.CreateResponsesMessage(HttpStatusCodeEnum.UnAuthorized.ToString("D"), Resource.AuthorizationFail, responseMessage);
}
return xxx.CommonClass.HttpResponses.GetHttpResponseMessage(HttpStatusCode.OK, responseMessage);
}
my mailer code->
bool status;
if (contentStream != null && fileName != null)
{
var i = 0;
foreach (var contentStrea in contentStream)
{
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(contentStrea, fileName[i].Trim());
mailMessage.Attachments.Add(attachment);
i++;
}
}
mailMessage.From = new MailAddress(ConfigurationManager.AppSettings["SenderMailAddress"]);
mailMessage.IsBodyHtml = true;
status = await SMTPCredentials(mailMessage);
return status;
}
See email screenshot here
I'm not sure, but try seeking the start of the stream before adding the attachment.
contentStrea.Seek(0, System.IO.SeekOrigin.Begin);
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(contentStrea, fileName[i].Trim());
I have an async action in a controller that look like this
public async Task<ActionResult> Register(MerchantRegistrationViewModel merchantRegistrationViewModel)
{
if (ModelState.IsValid)
{
//Some code
//SendMail
EmailManager em = new EmailManager("MerchantVerify.htm",merchant,"Verify Email");
await em.SendEmailAsync();
db.Merchants.Add(merchant);
await db.SaveChangesAsync();
return RedirectToAction("Success");
}
}
The code in the method em.SendEmailAsync()
public async Task SendEmailAsync()
{
GetEmailTemplate();
var emailBody = BuildEmailBodyForVerifyMerchant();
var emailToSend = BuildEmailMessage(emailBody, subject);
var client = new SmtpClient();
await client.SendMailAsync(emailToSend);
}
The problem I have noticed is with the method GetEmailTemplate() which contains this code block
private void GetEmailTemplate()
{
//Tried Option 1
//mailBody = System.IO.File.ReadAllText(HostingEnvironment.MapPath("/Content/MailText/" + mailTemplate));
//Tried Option 2
using (FileStream fs = new FileStream(HostingEnvironment.MapPath("/Content/MailText/" + mailTemplate), FileMode.Open))
using (StreamReader sr = new StreamReader(fs))
{
mailBody = sr.ReadToEnd();
}
}
If I comment this code block and I change the action to async or non async I get the email sent. If I uncomment any of the options mail is never received. I don't get any errors.
I suspect is has something to do with the way I am reading the template file.
public class EmailManager
{
private string mailTemplate;
private Merchant merchant;
private string mailBody = string.Empty;
private string subject;
public EmailManager()
{
}
public EmailManager(string mailTemplate, Merchant merchant, string subject)
{
this.mailTemplate = mailTemplate;
this.merchant = merchant;
this.subject = subject;
}
private void GetEmailTemplate()
{
//Get Mail Text Path
//mailBody = System.IO.File.ReadAllText(HostingEnvironment.MapPath("/Content/MailText/" + mailTemplate));
using (FileStream fs = new FileStream(HostingEnvironment.MapPath("/Content/MailText/" + mailTemplate),FileMode.Open ,FileAccess.Read, FileShare.Read))
using (StreamReader sr = new StreamReader(fs))
{
mailBody = sr.ReadToEnd(); // 1
}
}
private string BuildEmailBodyForVerifyMerchant()
{
//Replace Custom Variables for Email Body
Uri url = System.Web.HttpContext.Current.Request.Url;
string UrlLink = url.OriginalString.Replace(url.PathAndQuery, "");
merchant.ProviderUserKey = Guid.NewGuid().ToString();
UrlLink = String.Concat(UrlLink, "/");
var verifyUrl = UrlLink + "business/verify/" + merchant.ProviderUserKey.ToString();
//replace variables
mailBody = mailBody.Replace("~userLastName~", merchant.Name);
mailBody = mailBody.Replace("~name~", String.Format("{0} {1}", merchant.FirstName, merchant.LastName));
mailBody = mailBody.Replace("~companyName~", merchant.Name);
mailBody = mailBody.Replace("~dateOfRegistration~", merchant.DateOfRegistration.Value.ToShortDateString());
mailBody = mailBody.Replace("~verifyUrl~", verifyUrl);
mailBody = mailBody.Replace("~email~", merchant.Email);
return mailBody;
}
private MailMessage BuildEmailMessage(string body, string subject)
{
MailMessage msg = new MailMessage();
msg.From = new MailAddress("no-reply#mydomain.com");
msg.To.Add(new MailAddress(merchant.Email.ToString()));
msg.Subject = subject;
msg.Body = body;
return msg;
}
public async Task SendEmailAsync()
{
GetEmailTemplate();
var emailBody = BuildEmailBodyForVerifyMerchant();
var emailToSend = BuildEmailMessage(emailBody, subject);
var client = new SmtpClient();
await client.SendMailAsync(emailToSend);
}
}
Here is a refactor of the EmailManager given the provided example in the OP.
The methods were refactored to better express their dependencies and hopefully help in isolating what may be causing the problem in the GetEmailTemplate method.
public interface IEmailManager {
Task SendEmailAsync();
}
public class EmailManager : IEmailManager {
private string mailTemplate;
private Merchant merchant;
private string subject;
public EmailManager(string mailTemplate, Merchant merchant, string subject) {
this.mailTemplate = mailTemplate;
this.merchant = merchant;
this.subject = subject;
}
private async Task<string> GetEmailTemplateAsync(string mailTemplate) {
var mailBody = String.Empty;
//Get Mail Text Path
var path = HostingEnvironment.MapPath("/Content/MailText/" + mailTemplate);
//mailBody = System.IO.File.ReadAllText(HostingEnvironment.MapPath("/Content/MailText/" + mailTemplate));
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var sr = new StreamReader(fs)) {
mailBody = await sr.ReadToEndAsync();
}
return mailBody;
}
private string BuildVerifyEmailBodyForMerchant(string mailBody, Merchant merchant) {
//Replace Custom Variables for Email Body
var url = System.Web.HttpContext.Current.Request.Url;
var urlLink = url.OriginalString.Replace(url.PathAndQuery, "");
merchant.ProviderUserKey = Guid.NewGuid().ToString();
urlLink = String.Concat(urlLink, "/");
var verifyUrl = urlLink + "business/verify/" + merchant.ProviderUserKey.ToString();
//replace variables
mailBody = mailBody.Replace("~userLastName~", merchant.Name);
mailBody = mailBody.Replace("~name~", String.Format("{0} {1}", merchant.FirstName, merchant.LastName));
mailBody = mailBody.Replace("~companyName~", merchant.Name);
mailBody = mailBody.Replace("~dateOfRegistration~", merchant.DateOfRegistration.Value.ToShortDateString());
mailBody = mailBody.Replace("~verifyUrl~", verifyUrl);
mailBody = mailBody.Replace("~email~", merchant.Email);
return mailBody;
}
private MailMessage BuildEmailMessage(string body, string subject, Merchant merchant) {
var msg = new MailMessage();
msg.From = new MailAddress("no-reply#mydomain.com");
msg.To.Add(merchant.Email.ToString());
msg.Subject = subject;
msg.Body = body;
return msg;
}
public async Task SendEmailAsync() {
var emailTemplate = await GetEmailTemplateAsync(mailTemplate);
var emailBody = BuildVerifyEmailBodyForMerchant(emailTemplate, merchant);
var emailToSend = BuildEmailMessage(emailBody, subject, merchant);
using (var client = new SmtpClient()) {
await client.SendMailAsync(emailToSend);
}
}
}
I'm trying to use the new Toggl API (v8) with .NET C#. I've based my code on the example from litemedia (http://litemedia.info/connect-to-toggl-api-with-net), but it was originally created for version 1 of the API.
private const string TogglTasksUrl = "https://www.toggl.com/api/v8/tasks.json";
private const string TogglAuthUrl = "https://www.toggl.com/api/v8/me"; //sessions.json";
private const string AuthenticationType = "Basic";
private const string ApiToken = "user token goes here";
private const string Password = "api_token";
public static void Main(string[] args)
{
CookieContainer container = new CookieContainer();
var authRequest = (HttpWebRequest)HttpWebRequest.Create(TogglAuthUrl);
authRequest.Credentials = CredentialCache.DefaultCredentials;
authRequest.Method = "POST";
authRequest.ContentType = "application/x-www-form-urlencoded";
authRequest.CookieContainer = container;
string value = ApiToken; //= Convert.ToBase64String(Encoding.Unicode.GetBytes(ApiToken));
value = string.Format("{1}:{0}", Password, value);
//value = Convert.ToBase64String(Encoding.Unicode.GetBytes(value));
authRequest.ContentLength = value.Length;
using (StreamWriter writer = new StreamWriter(authRequest.GetRequestStream(), Encoding.ASCII))
{
writer.Write(value);
}
try
{
var authResponse = (HttpWebResponse)authRequest.GetResponse();
using (var reader = new StreamReader(authResponse.GetResponseStream(), Encoding.UTF8))
{
string content = reader.ReadToEnd();
}
HttpWebRequest tasksRequest = (HttpWebRequest)HttpWebRequest.Create(TogglTasksUrl);
tasksRequest.CookieContainer = container;
//var jsonResult = string.Empty;
var tasksResponse = (HttpWebResponse)tasksRequest.GetResponse();
MemoryStream ms = new MemoryStream();
tasksResponse.GetResponseStream().CopyTo(ms);
//using (var reader = new StreamReader(tasksResponse.GetResponseStream(), Encoding.UTF8))
//{
// jsonResult = reader.ReadToEnd();
//}
ms.Seek(0, SeekOrigin.Begin);
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Task));
var tasks = ser.ReadObject(ms) as List<Task>;
ms.Close();
//var tasks = DataContractJsonConvert.DeserializeObject<Task[]>(jsonResult);
foreach (var task in tasks)
{
Console.WriteLine(
"{0} - {1}: {2} starting {3:yyyy-MM-dd HH:mm}",
task.Project.Name,
task.Description,
TimeSpan.FromSeconds(task.Duration),
task.Start);
}
}
catch (System.Exception ex)
{
throw;
}
}
The following line is returning a 404 error.
var authResponse = (HttpWebResponse)authRequest.GetResponse();
Here is code that works. Since I was looking for this answer recently there might still be others as lost as me.
Notes: I used Encoding.Default.GetBytes() because Encoding.Unicode.GetBytes() did not give me a correct result on my .NET string. I hope it doesn't depend on the default setup of Visual Studio.
The content-type is "application/json".
Sorry, I haven't tried a POST version yet.
string ApiToken = "user token goes here";
string url = "https://www.toggl.com/api/v8/me";
string userpass = ApiToken + ":api_token";
string userpassB64 = Convert.ToBase64String(Encoding.Default.GetBytes(userpass.Trim()));
string authHeader = "Basic " + userpassB64;
HttpWebRequest authRequest = (HttpWebRequest)WebRequest.Create(url);
authRequest.Headers.Add("Authorization", authHeader);
authRequest.Method = "GET";
authRequest.ContentType = "application/json";
//authRequest.Credentials = CredentialCache.DefaultNetworkCredentials;
try
{
var response = (HttpWebResponse)authRequest.GetResponse();
string result = null;
using (Stream stream = response.GetResponseStream())
{
StreamReader sr = new StreamReader(stream);
result = sr.ReadToEnd();
sr.Close();
}
if (null != result)
{
System.Diagnostics.Debug.WriteLine(result.ToString());
}
// Get the headers
object headers = response.Headers;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message + "\n" + e.ToString());
}