Sendgrid makes links to others - Get them made right - c#

That's how I've added a regular link to the bottom of email if the customer would like to unsubscribe from newsletter, but Sendgrid has turned it into an incredibly long email.
Then my question is: How can I change it to my own link or link that is smaller? - I'd just like to make it shorter or less so customers do not think it's spam
It's like I can not upload image so I can show it here.
Code:
var viewModel = new EmailModel
{
getUrl = link, //link to remove user from newsletterlist here
Title = title, //title for email
FullName = item.Navn, //name on the user
text = text.ToHtmlString() //text value
};
var resultMail = await _viewRenderService.RenderToStringAsync("~/Views/Templates/newMail.cshtml", viewModel);//return Null here
MailMessageControl mail = new MailMessageControl();
mail.SetCredentials(m.azureName(), m.password());
mail.SetSender(m.mailFrom());
mail.AddAddressSee(item.Brugernavn);
mail.SetSubject(title);
mail.SetBody(Regex.Replace(resultMail, "<[^>]*>", ""));
mail.SendEmail();
await Task.Delay(2200);

Related

How do you create a PDF after submitting a form and attach it to an automated email in ASP.NET MVC C#?

I am having the hardest time figuring out how to create a pdf and attach it to an automated email. I thought it wouldn't be that hard but have quickly found out that it is much more complex than I imagined. Anyways, what I am doing is I have an order form, and when the customer fills out an order and submits it, I want it to generate a PDF for that order and attach it to an automated confirmation email. I am currently using Rotativa to generate the pdf and if I just ran the action result for generating it, it works perfectly fine which looks something like this:
public ActionResult ProcessOrder(int? id)
{
string orderNum = "FulfillmentOrder" + orderDetail.OrderID + ".pdf";
var pdf = new ActionAsPdf("OrderReportPDF", new { id = orderDetail.OrderID }) { FileName = orderNum };
return pdf;
}
When I added the function to send an automated email after the order form was submitted, that works perfectly fine with just the email by itself. But I can't seem to figure out how to generate the pdf and attach it to the email. The report view that gets the data from the order form is called "OrderReportPDF". My order form is called "Checkout", but the action result I use for this is called "Process Order". I've taken out the code in this function that is for the order form as it is not applicable. The section of my code for sending the email after the form is submitted is:
public ActionResult ProcessOrder(int? id)
{
//Send a confirmation email
var msgTitle = "Order Confirmation #" + orderDetail.OrderID;
var recipient = JohnDoe;
var fileAttach = //This is where I can't figure out how to attach//
var fileList = new string[] { fileAttach };
var errorMessage = "";
var OrderConfirmation = "Your order has been placed and is pending review." +
" Attached is a copy of your order.";
try
{
// Initialize WebMail helper
WebMail.SmtpServer = "abc.net";
WebMail.SmtpPort = 555;
WebMail.UserName = recipient;
WebMail.Password = "12345";
WebMail.From = "orders#samplecode.com";
// Send email
WebMail.Send(to: "orders#samplecode.com",
subject: msgTitle,
body: OrderConfirmation,
filesToAttach: fileList
);
}
catch (Exception ex)
{
errorMessage = ex.Message;
}
//5. Remove item cart session
Session.Remove(strCart);
return View("OrderSuccess");
}
I have been able to find very few articles on this issue using Rotativa and the ones I have found don't work for what I'm doing. Maybe Rotativa won't work for this, I'm hoping it does because I've designed my pdf report it generates from it, and not sure if doing it another way will screw up my formatting of it or not. As you can see at the bottom of the code, I return the view to an "OrderSuccess" page. When I try to implement the first code into the second code, it won't let me "return pdf" to execute the ActionAsPdf that generates the pdf when I do the "return View("OrderSuccess")". It only lets me do one or the other. If anybody knows how I can accomplish this, I need some help. I appreciate any suggestions or feedback. I'm pretty new to this so please be patient with me if I don't understand something.
Here is the updated code that fixed my problem and created the pdf, then attached it to an automated email once the order form was submitted:
public ActionResult ProcessOrder(int? id)
{
//1. Generate pdf file of order placed
string orderNum = "FulfillmentOrder" + orderDetail.OrderID + ".pdf";
var actionResult = new Rotativa.ActionAsPdf("OrderReportPDF", new { id = orderDetail.OrderID }) { FileName = orderNum };
var PdfAsBytes = actionResult.BuildFile(this.ControllerContext);
//2. Send confirmation email
var msgTitle = "Order Confirmation #" + orderDetail.OrderID;
var OrderConfirmation = "Your order has been placed and is pending review.<br />" +
" Attached is a copy of your order." +
using (MailMessage mail = new MailMessage())
{
mail.From = new MailAddress("orders#samplecode.com");
mail.To.Add("orders#samplecode.com");
mail.Subject = msgTitle;
mail.Body = OrderConfirmation;
mail.IsBodyHtml = true;
//STREAM THE CONVERTED BYTES AS ATTACHMENT HERE
mail.Attachments.Add(new Attachment(new MemoryStream(PdfAsBytes), orderNum));
using (SmtpClient smtp = new SmtpClient("abc.net", 555))
{
smtp.Credentials = new NetworkCredential("orders#samplecode.com", "password!");
smtp.EnableSsl = true;
smtp.Send(mail);
}
}
//3. Remove item cart session
Session.Remove(strCart);
return View("OrderSuccess");
}
Thank you again to the people that helped and got me pointed in the right direction! Also, a quick shout out to #Drewskis who posted this answer in convert Rotativa.ViewAsPdf to System.Mail.Attachment where I was able to use it to solve my issue!

Send xsl doc in body of email

Programming would be much easier without users...
What I really need to be able to do is:
Put the content of a web page (including styles) into the body of an email and also set the subject.
OR
Send the current user an email containing the body of a web page.
I really don't care how this is implemented -- server or client side. I've not come up with any good way of client side besides trying to push the web page into the clipboard for the users to then paste into their email.
App Background
I wrote a web site using c#, ts, angular. The site manages xml documents.
The users can select a document and click the "Human Readable" button or the "XML" button. The "Human Readable" is xml with xsl to make it look pretty for the humans. The XML button is apparently for non-humans.
The "Human Readable" version opens in another browser tab.
The users want a new "email" button for emailing the human readable. The person clicking the email button has access to my web site but the recipient may not.
I've attempted educating my users to do Ctrl+A, Ctrl+C, open email, Ctrl+V but this is beyond most of their capabilities.
I have tried so many different ways to accomplish this and all have failed.
I currently do a mailto link which opens their email and the body contains a link to the Human Readable.
Here's what I've tried so far -- this may not be a conclusive list of my attempts as I've been at this for a few days now.
I've tried putting a button in the human readable (xsl with javascript) in an attempt to copy the resulting html into the clipboard for the users to paste.
A button on the web site to scrape an iFrame into the clipboard
Many iterations of javascript copy/paste techniques
a c# controller that does a ReadAsStringAsync().Result function (which I will post below because I like that solution the best so far...
Option #4 I'm partial to and I got almost working -- if it weren't for that pesky xsl not getting formatted it would probably work. My results are the data being presented without xml tags and no styles.
[ActionName("PostEmailHumanReadable")]
public void EmailHumanReadable(List<DocumentVM> documents)
{
foreach (var document in documents)
{
var docId = document.document.DocId;
var docTypeId = document.document.DocTypeId;
var co = string.Empty;
var order = string.Empty;
var name = string.Empty;
var po = string.Empty;
// get the data for the subject line
using (var efUoW = new EFUnitOfWork(EDIEnvironment.EDIEnvironment.Instance.ConnectionString))
{
var doc = efUoW.DocumentRepository.GetById(docId);
co = doc.CompanyId.ToString();
var orders = efUoW.DocumentOrderRepository.GetByDocumentID(docId).ToList();
if (!string.IsNullOrEmpty(doc.Source_Order))
order = doc.Source_Order;
else
order = "n/a";
foreach (var o in orders)
order += string.Format("{0} ", o.OrderId);
//order = string.Join(",", doc.DocumentOrders.Select(q => q.OrderId).ToList());
name = doc.BillToName;
name = doc.PurchaseOrder;
}
var subject = string.Format("{0}, {1}, {2}, {3}", co, order, name, po);
// get the human readable
var hrResponse = GetFile(docId, docTypeId);
var hrText = hrResponse.Content.ReadAsStringAsync().Result;
// format the url
var url = string.Format("<a href='/api/Documents/Getfile?DocId={0}&DocTypeId={1}'>click here to open the jEDI Human Readable</a><br><br>", docId, docTypeId);
// find the current user's email address
var users = new List<string>();
users.Add(AppUser.ADUserName);
//var to = EmailUtility.GetEmailID(users);
// and finally send the email
EmailUtility.SendEmail(EmailUtility.GetEmailID(users), null, subject, url + hrText);
}
}
[ActionName("GetFile")]
public HttpResponseMessage GetFile(int DocId, int DocTypeId)
{
if (DocTypeId == (int)DocumentTypeEnum.EDI850)
{
using (var efUoW = new Factory_UOW().EF_UOW())
{
var doc = efUoW.DocumentRepository.GetById(DocId);
var xdoc = XDocument.Parse(doc.Message);
var proc = new XProcessingInstruction("xml-stylesheet", "type='text/xsl' href='/EDI850.xsl'");
xdoc.Root.AddBeforeSelf(proc);
var response = new HttpResponseMessage();
response.Content = new System.Net.Http.StringContent(xdoc.ToString());
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
response.Content.Headers.Add("X-UA-Compatible", "IE=edge");
return response;
}
I would be very grateful for any assistance in getting this to work.
And, yes, I know I shouldn't do the Async().Result -- blocking and all that... Let's just get this working first, shall we?

Adding forward text to email

I'm having a slight problem with adding text to forwarding emails. This is my current code:
private void ForwardFunction(Outlook.MailItem email)
{
Outlook.MailItem forwardEmail = ((Outlook._MailItem)email).Forward();
Outlook.Inspector forwardInsp = forwardEmail.GetInspector;
Word.Document forwardDoc = forwardInsp.WordEditor;
Word.Range forwardRange = forwardDoc.Range(0,1);
string forwardText = "This is some text";
forwardRange.Text = forwardText + forwardRange.text
newEmail.Recipients.Add("myemail");
forwardEmail.Save();
((Outlook._MailItem)forwardEmail).Send();
}
I've gone through it and it does add the text to the range, but when I receive the forwarded email it doesn't contain any of the additional text. I've used similar code to edit current emails that the user is editing (New, Replies/Forwards, InlineResponses) with success, but the email being passed to the function is the currently selected email in the inbox. Not sure if this matters, maybe because it's not being edited by the user.
I couldn't find a specific way to add new text to a programmatically forwarded email.
For anyone else interested in this, I ended up using the .HTMLBody. It seems that using the .GetInspector either gets the inspector of the _email instead of fEmail and you can't edit it or it gets the correct inspector but it can't edit it. Either way, using the .HTMLBody seems to get around it.
Outlook.MailItem fEmail = ((Outlook._MailItem)_email).Forward();
string forwardText;
forwardText = "class=MsoNormal>";
forwardText += "This is my forwarded message";
forwardText += "Bonus hyper link <a href='" + hyperlinkText + "'>" + hyperlinkText + "</a>";
var regex = new Regex(Regex.Escape("class=MsoNormal>"));
fEmail.HTMLBody = regex.Replace(fEmail.HTMLBody, forwardText, 1);
fEmail.Save();
fEmail.AutoForwarded = true;
((Outlook._MailItem)fEmail).Send();

code to subscribe a user to a list in mailchimp

When I execute the below code, the mail id is not added to the list, but the "result" parameter contains the value of Email,EUIdl, LEId. Anyone can give the exact code. The code taken from
https://github.com/danesparza/MailChimp.NET
MailChimpManager mc = new MailChimpManager("5323a23b12022d250c23c48253641dd5-us8");
// Create the email parameter
EmailParameter email = new EmailParameter()
{
Email = "riyas.k13#gmail.com"
};
EmailParameter results = mc.Subscribe("33cacee7d8", email);
With the MCAPI this is the call to subscribe to a list, you might want to check all the options in the subscribeOptions, and determine your required Merge values
MCApi mc = new MCApi(ConfigurationManager.AppSettings["MCAPIKey"], false);
var subscribeOptions = new Opt<List.SubscribeOptions>(new List.SubscribeOptions { SendWelcome = true, UpdateExisting = true });
var merges = new Opt<List.Merges>(new List.Merges { { "FNAME", [Subscriber FirstName here] }, { "LNAME", [Subscriber lastName here] } });
if (mc.ListSubscribe(ConfigurationManager.AppSettings["MCListId"], [Subscriber email ], merges, subscribeOptions))
// The user is subscribed Do Something
I had the same issue where the code seemed to work but no email was added to the list. The code does work by the way.
When a new email address is added to the mail list MailChimp sends out a confirmation email to that address, which you need need to confirm naturally.
If you don't do this the new email address won't be added to the list. If you didn't receive any email at the target address check the spam folder or see if any filters have accidentally caught it without you realising.
Sad to say I spent a good few hours going around in circles because of this.
This depends on maichimp list setting when you created the list. There is something called "ask users to confirm the subscription". By default, if admin checked this option, after importing, the users will receive confirmation emails. New added user names will be added only if they confirmed.
If you don't want to sent confirmation emails but directly added new users. Set "DoubleOptIn" to false.
/*
Set subscribe options
*/
MailChimp.Types.List.SubscribeOptions option = new MailChimp.Types.List.SubscribeOptions();
option.UpdateExisting = true;
option.DoubleOptIn = false;
List<MailChimp.Types.List.Merges> lstMerges = new List<MailChimp.Types.List.Merges>();
/*
Merge new users here.
*/
returnStatus = api.ListBatchSubscribe("your MailChimp List ID", lstMerges, option);

Sitecore workflow approval/rejection emails

We are working on implementing some custom code on a workflow in a Sitecore 6.2 site. Our workflow currently looks something like the following:
Our goal is simple: email the submitter whether their content revision was approved or rejected in the "Awaiting Approval" step along with the comments that the reviewer made. To accomplish this we are adding an action under the "Approve" and "Reject" steps like so:
We are having two big issues in trying to write this code
There doesn't seem to be any easy way to determine which Command was chosen (the workaround would be to pass an argument in the action step but I'd much rather detect which was chosen)
I can't seem to get the comments within this workflow state (I can get them is the next state though)
For further context, here is the code that I have so far:
var contentItem = args.DataItem;
var contentDatabase = contentItem.Database;
var contentWorkflow = contentDatabase.WorkflowProvider.GetWorkflow(contentItem);
var contentHistory = contentWorkflow.GetHistory(contentItem);
//Get the workflow history so that we can email the last person in that chain.
if (contentHistory.Length > 0)
{
//contentWorkflow.GetCommands
var status = contentWorkflow.GetState(contentHistory[contentHistory.Length - 1].NewState);
//submitting user (string)
string lastUser = contentHistory[contentHistory.Length - 1].User;
//approve/reject comments
var message = contentHistory[contentHistory.Length - 1].Text;
//sitecore user (so we can get email address)
var submittingUser = sc.Security.Accounts.User.FromName(lastUser, false);
}
I ended up with the following code. I still see no good way to differentiate between commands but have instead implemented two separate classes (one for approve, one for reject):
public void Process(WorkflowPipelineArgs args)
{
//all variables get initialized
string contentPath = args.DataItem.Paths.ContentPath;
var contentItem = args.DataItem;
var contentWorkflow = contentItem.Database.WorkflowProvider.GetWorkflow(contentItem);
var contentHistory = contentWorkflow.GetHistory(contentItem);
var status = "Approved";
var subject = "Item approved in workflow: ";
var message = "The above item was approved in workflow.";
var comments = args.Comments;
//Get the workflow history so that we can email the last person in that chain.
if (contentHistory.Length > 0)
{
//submitting user (string)
string lastUser = contentHistory[contentHistory.Length - 1].User;
var submittingUser = Sitecore.Security.Accounts.User.FromName(lastUser, false);
//send email however you like (we use postmark, for example)
//submittingUser.Profile.Email
}
}
I have answered a very similar question.
Basically you need to get the Mail Workflow Action and then you need to further extend it to use the original's submitter's email.
Easiest way to get the command item itself is ProcessorItem.InnerItem.Parent
This will give you the GUID for commands like submit, reject etc.
args.CommandItem.ID
This will give you the GUID for states like Draft, approved etc.
args.CommandItem.ParentID

Categories