I'm trying to use Mandrill templates to send order tracking emails.
Using the mc:edit works well for simple text like <span mc:edit="ship_id">ship_id</span><br>
I was wondering if there was a way to pass the href link in a variable i.e. tracking_url
<a class="mcnButton " title="Track order" href=tracking_url target="_blank" style="font-weight: bold;text-align: center;">Track Order</a>
I'm using Djrill for Django and here's the code which sends the email so far, and I'd like to add tracking_url as a template_content variable or something similar
msg = EmailMessage(subject="Track your order", from_email="admin#example.com", to=[user.email])
msg.template_name = "order-sent"
msg.template_content = {'order_id' : order_id, 'order_date' : order_date, 'order_type' : order_type, 'first_name' : user.first_name, 'last_name' : user.last_name, 'phone' : user.info.phone,
'd_street' : d.street, 'd_zipcode' : d.zipcode, 'd_city' : d.city, 'd_country' : d.country}
msg.send()
It seems possible using the AddGlobalVariable method (read here) but I can't figure out how to use it..
I have an Email Dispatcher that uses MandripApp to send normal emails (as SMTP) as well to send emails using the template.
I do not know how to pass what you are asking, as I'm not using mc:edit attributes any longer (as my users will never edit the template themselves, me or a developer will) but I can provide you help with the global variables.
Global variables are the same as Mailchimp vars, like *|EMAIL|* and this is what I do:
var mergeVars = Dictionary<string, string>();
mergeVars.Add("ORDER_ID", orderId);
mergeVars.Add("CUSTOMER_NAME", fullname);
mergeVars.Add("CUSTOMER_FNAME", fullname.Contains(" ") ? fullname.Split(' ')[0] : fullname);
mergeVars.Add("CUSTOMER_EMAIL", email);
for example, a hole table:
StringBuilder sb = new StringBuilder();
foreach (ProductInfo pi in products)
{
sb.Append("<tr>");
sb.AppendFormat("<td style=\"text-align:left;\"><img src=\"http://dynassets1.gavekortet.dk/{2}/products/trans/{1}_1.png\" alt=\"{0}\" /></td>", pi.Title, pi.ID, shopId);
sb.AppendFormat("<td style=\"text-align:left;\">{0} x {1}</td>", pi.Qty, pi.Title);
sb.AppendFormat("<td style=\"text-align:right;\">{0:N2}</td>", double.Parse(pi.CardValue));
sb.Append("</tr>");
}
mergeVars.Add("ITEMS_LIST", sb.ToString());
in my template in MandrillApp I simply have (for the table part):
<table style="width: 100%; padding: 0 30px;">
<thead>
<tr>
<th style="width:75px; text-align:left;">Gavekort</th>
<th style="width:75px; text-align:left;">Ordreoversigt</th>
<th style="width:75px; text-align:right;">Værdi (kr.)</th>
</tr>
</thead>
<tbody>
*|ITEMS_LIST|*
</tbody>
</table>
and in code you do:
var tmplMessage = new MandrillSendTemplateItem();
tmplMessage.key = password;
tmplMessage.message = new MessageItem();
// Email Destination
tmplMessage.message.to = new List<MessageToItem>();
tmplMessage.message.to.Add(new MessageToItem() { name = destinationName, email = destinationEmail, type = "to" });
tmplMessage.message.to.Add(new MessageToItem() { name = "Bruno Alexandre", email = "my_email#domain.com", type = "bcc" }); // always send me a copy so I know what's going on
// Global Variables
tmplMessage.message.global_merge_vars = new List<TemplateContentItem>();
tmplMessage.message.global_merge_vars.Add(
new TemplateContentItem() {
name = "TASKCOMPLETE",
content = DateTime.UtcNow.ToString("dd MMM yyyy HH:mm") });
// Global Variables passed in properties
if (properties != null)
{
foreach (var p in properties)
{
tmplMessage.message.global_merge_vars.Add(
new TemplateContentItem() { name = p.Key, content = p.Value });
}
}
and send the email.
I hope it helps you doing what you need.
Note that you only pass the name of the global variable in your code, but in the template you need to call it wrapping it with |* and *| so:
tmplMessage.message.global_merge_vars.Add(
new TemplateContentItem() {
name = "TASKCOMPLETE",
content = DateTime.UtcNow.ToString("dd MMM yyyy HH:mm") });
will be accessible in the template as:
<span class="completed">*|TASKCOMPLETE|*</span>
This post is pretty old but I thought I'd share my answer to this in case someone else stumbles upon here.
If you are using the Mandrill API, you need to actually send the variable values in the "global_merge_vars" or "merge_vars" keys. DO NOT use the template_content. Mandrill API was rather unintuitive this way.
So your content would remain the same with a variable:
*|ITEMS_LIST|*
Then your JSON body should have something like:
"global_merge_vars": [
{
"name": "ITEMS_LIST",
"content": "This is a list"
}
],
source: How to add params to all links in a mandrill template through API?
Related
What is the correct way of getting PidLidEndRecurrenceDate values using Ews. below code does not give proper result. property details that i am looking is https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxprops/816378cf-07ef-4926-b7d2-53475792403d
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Credentials = new WebCredentials("X#X.com", "XXX");
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
ItemView view = new ItemView(10);
Guid MyPropertySetId = new Guid("{6ED8DA90-450B-101B-98DA-00AA003F1305}");
int intValue = Convert.ToInt32("0x0000000F", 16);
ExtendedPropertyDefinition extendedPropertyDefinition =
new ExtendedPropertyDefinition(MyPropertySetId, intValue, MapiPropertyType.Integer);
view.PropertySet =
new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, extendedPropertyDefinition);
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Calendar, view);
foreach (Item item in findResults.Items)
{
Console.WriteLine(item.Subject);
if (item.ExtendedProperties.Count > 0)
{
// Display the extended name and value of the extended property.
foreach (ExtendedProperty extendedProperty in item.ExtendedProperties)
{
Console.WriteLine(" Extended Property Name: " + extendedProperty.PropertyDefinition.Name);
Console.WriteLine(" Extended Property Value: " + extendedProperty.Value);
}
}
}
That property is set on the Meeting invite messages only not on the Master instance of the Calendar Appointments which is what you seem to be looking at. For the Master instances you should just be able to use the strongly typed property https://learn.microsoft.com/en-us/dotnet/api/microsoft.exchange.webservices.data.recurrence.enddate?redirectedfrom=MSDN&view=exchange-ews-api#Microsoft_Exchange_WebServices_Data_Recurrence_EndDate
It you wanted to view the property you have above search the SentItems Folder for invites with recurrences (with Enddates) and that's where you will see it. Or probably easier just look at the messages with a Mapi editor like OutlookSpy or MFCMAPI and you will see the properties available.
So, im a little bit lost here and i need some help.
I have a json that come from the server with data that i dont know.
Based on that i found a solution to display the data on html here on SO:
https://stackoverflow.com/a/50352965/9721446
But the problem is that each "item" is an entry from array, so if i ngfor array, it outputs each line as an item, and i want the item to be all entries of each result.
heres the html:
<ng-container *ngFor="let item of singleArray | paginate: { itemsPerPage:411, currentPage: p} ">
<!-- All the entries -->
<div class="w3-container">
<!-- Table view-->
<table class="center">
<tr *ngIf="!item.tag.includes('URL') && !item.tag.includes('linkChal')">
<td><div class="col-xs-auto thick">{{item.tag.toLowerCase() | translate}}</div></td>
<td class="tab">{{item.value}}</td>
</tr>
<tr *ngIf="item.tag.includes('URL')">
<td>Link da entrada: </td>
<td> - Ver mais -</td>
</tr>
<tr *ngIf="item.tag.includes('linkChal')">
<td>Link do Challenge: </td>
<td> - Challenge -</td>
</tr>
</table>
<div style="background-color: #ff7d2a">
<ul *ngIf=" item.tag.includes('---------')"><p>New Entry</p></ul>
</div>
</div>
</ng-container>
Ts:
for(let i in res)
{
//array with entities from json
this.entity.push(i);
for(let j in res[i])
{
let val = Number(j)+1;
this.cont.push(i +" - nº: " + val );
this.singleArray.push({
tag: i,
value: val
});
for(let t in res[i][j])
{
this.test.push(t);
this.cont.push(t +" - "+ this.responseList[i][j][t]) ;
if(t.split(".",2)[1] === "CompositeId")
{
this.test.push("URL:");
//Get the id
this.cont.push(this.moduleName + "/" + t.split(".",2)[0] + "/" + this.responseList[i][j][t].match(/=(.*)_/)[1]);
//debugger;
this.singleArray.push({
tag: "URL:",
value: this.moduleName + "/" + t.split(".",2)[0] + "/" + this.responseList[i][j][t].match(/=(.*)_/)[1]
});
}
else if(t.split(".",2)[1] === "Challenge")
{
this.singleArray.push({
tag: "linkChal",
value: this.moduleName + "/" +t.split(".",2)[1] + "/" + this.responseList[i][j][t].match(/=(.*)_/)[1]
});
}
else {
this.singleArray.push({
tag: t,
value: this.responseList[i][j][t]
});
}
}
this.test.push("\n");
this.cont.push("\n");
this.singleArray.push({
tag: "---------\n",
value: "--------\n"
});
//it ends an item here
}
}
Heres the output i have with that:
Each one line is an entry from the array, the big question is, how to transform all lines/entries until "New Entry" and made an single item to ngfor and display data into a card that i already have..)
I've tried to create an array and push the singleArray into it (hoping each entry of that new array was an item that i want), at the end of for(let j in res[i]) on .ts but it just repeated all the entries creating a bunch of entries..
here, at the end of that for, i've tried to push an array with something, then ngfor it (it gives me the number items that i want, but then i dont have the results to access them..)
Has anyone had this problem before?
thanks in advance
Edit: here's what singleArray looks like:
Your best bet here is to follow the single responsibility principal and separate the concerns of each class.
Stop trying to do this all in the view and separate out the responsibility of formatting the data and the problem will seem much simpler.
Make a new class to define the model you want your view to use
Have your view implement this new ideal model that you control
Generate some test data to make get this looking like what you want
Create a new class who's entire responsibility is to turn the external model from the api response into this new internal model
json2ts may help generate a better external model from the response, but it may not be of much use in this case
Once you have done the above, based on your sample output, it should be fairly simple to convert from the external model into the internal model. It's hard to convey this, but assuming the hyphens are the item separator you could simply do something like the following:
const externalItems = // data from api
const internalItems = [];
let currentInternalItem = {};
externalItems.forEach(item => {
if (item.tag.startsWith('---------')) {
internalItems.push(currentInternalItem);
currentInternalItem = {};
} else {
currentInternalItem[item.tag] = item.value;
}
});
This would group the array back into an object that you can use in your view.
I think I'm complicating too much.. The objective here is to display what comes from JSON into specific locations, like a card, with header and content, to better display the results.
I have a service that gives me a JSON, that i never knows what inside, that depends on the search term and can bring much information. For example:
If the term is "Idea":
If the term is Challenge:
My .ts file is only console.log what comes from the api.
ngOnInit() {
var setting = {setting to connect the server..}
enter code here
$.ajax(settings).done((rest) => this.response(rest));
}
response(res){
console.log(res);
}
How can i display that data the way i want?
Sorry for the long post, and for not beeing objective on the main question.
actually i need to parse a HTML table and that table contains HTML character, you can see in image.
i need each cell data with that special character also. Right now when i am parsing the table with XPath its ignore that cell and returns that cell value as empty.
Both Image attached here.
$table_head = $summary_nodes->childNodes->item(0);
$table_body = $summary_nodes->childNodes->item(1);
$head = [];
$body = [];
// print_r($table_head);
foreach($table_head->childNodes as $h_index => $h_node){
$head_temp = [];
foreach($h_node->childNodes as $cell_index => $cell){
$head_temp[] = trim($cell->nodeValue);
}
$head[] = $head_temp;
}
foreach($table_body->childNodes as $b_index => $b_node){
$body_temp = [];
// print_r($b_node);
foreach($b_node->childNodes as $cell_index => $cell){
print_r($cell);
$body_temp[] = trim($cell->nodeValue);
}
$body[] = $body_temp;
}
return ['table_ready'=>array_merge([$head[count($head)-1]], $body), 'headers'=> $head];
Hello friends I got answer for this, actually what is happening we are adding HTML entity inside our real data that's why while passing it's conflicting with HTML content and while parsing parser remove automatically that HTML entities so we have to make sure our real data does not have any HTML entities if we are using or if we need any entity which is similar to HTML entity please try to use they are HTML entity code.
I am experimenting with a Firefox extension that will load an arbitrary URL (only via HTTP or HTTPS) when certain conditions are met.
With certain conditions, I just want to display a message instead of requesting a URL from the internet.
I was thinking about simply hosting a local webpage that would display the message. The catch is that the message needs to include a variable.
Is there a simple way to craft a local web page so that it can display a variable passed to it in the URL? I would prefer to just use HTML and CSS, but adding a little inline javascript would be okay if absolutely needed.
As a simple example, when the extension calls something like:
folder/messageoutput.html?t=Text%20to%20display
I would like to see:
Message: Text to display
shown in the browser's viewport.
You can use the "search" property of the Location object to extract the variables from the end of your URL:
var a = window.location.search;
In your example, a will equal "?t=Text%20to%20display".
Next, you will want to strip the leading question mark from the beginning of the string. The if statement is just in case the browser doesn't include it in the search property:
var s = a.substr(0, 1);
if(s == "?"){s = substr(1);}
Just in case you get a URL with more than one variable, you may want to split the query string at ampersands to produce an array of name-value pair strings:
var R = s.split("&");
Next, split the name-value pair strings at the equal sign to separate the name from the value. Store the name as the key to an array, and the value as the array value corresponding to the key:
var L = R.length;
var NVP = new Array();
var temp = new Array();
for(var i = 0; i < L; i++){
temp = R[i].split("=");
NVP[temp[0]] = temp[1];
}
Almost done. Get the value with the name "t":
var t = NVP['t'];
Last, insert the variable text into the document. A simple example (that will need to be tweaked to match your document structure) is:
var containingDiv = document.getElementById("divToShowMessage");
var tn = document.createTextNode(t);
containingDiv.appendChild(tn);
getArg('t');
function getArg(param) {
var vars = {};
window.location.href.replace( location.hash, '' ).replace(
/[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
function( m, key, value ) { // callback
vars[key] = value !== undefined ? value : '';
}
);
if ( param ) {
return vars[param] ? vars[param] : null;
}
return vars;
}
Consider this HTML table:
<table id="build-table">
<tr>
<th>Build ID</th>
<th>Build Time</th>
</tr>
<tr>
<td>
5.1
</td>
<td>02.06.2011 13:33:03</td>
</tr>
</table>
How would I verify in WatiN that the table has the correct headers (Build ID and Build Time), and the correct content (in this case, one row containing the given hyperlink and date string)?
Sorry, we created a custom TableHandler, using the basic table building blocks: Here is the sample code:
public TableController(Regex tableControlId)
{ InitializeMembers(Find.ById(tableControlId), true); }
private void InitializeMembers(WatiN.Core.Constraints.AttributeConstraint tableControlId, bool hasColumnHeaders)
{
if (tableControlId == null)
{
throw new ArgumentNullException("tableControlId", "'tableControlId' passed in should not be null.");
}
WatiN.Core.Constraints.AttributeConstraint newTableControlId = tableControlId;
Assert.IsTrue(IE.Table(newTableControlId).Exists, "Table with id '" + newTableControlId.ToString() + "' does not exist on this page.");
_controlId = tableControlId;
_hasColumnHeaders = hasColumnHeaders;
_columnHeaders = (hasColumnHeaders) ? GetTableColumnHeaders() : null;
_totalRows = Table.TableRows.Count;
_totalColumns = GetAllColumnDataFromRow((TableRow)Table.TableRows[0], hasColumnHeaders).Count;
}
private StringCollection GetTableColumnHeaders()
{
return GetAllColumnDataFromRow((TableRow)Table.TableRows[0], true);
}
private StringCollection GetAllColumnDataFromRow(TableRow tableRow, bool isTableHeaderRow)
{
StringCollection RowValues = new StringCollection();
if (tableRow == null)
{
for (int colCounter = 0; colCounter < this.TotalColumns; colCounter++) RowValues.Add(String.Empty);
}
if (isTableHeaderRow)
{
foreach (Element e in tableRow.Elements)
{
if (e.TagName == "TH")
{
RowValues.Add(e.Text);
}
}
}
else
{
foreach (TableCell tc in tableRow.TableCells)
{
if (String.IsNullOrEmpty(tc.Text))
{
RowValues.Add(String.Empty);
}
else
{
RowValues.Add(tc.Text);
}
}
}
//fill up for the missing cells, if any, with blanks
int actualCellsInRow = tableRow.TableCells.Count;
int expectedCellsInRow = this.TotalColumns;
for (int colCounter = actualCellsInRow; colCounter < expectedCellsInRow; colCounter++)
{
RowValues.Add(String.Empty);
}
return RowValues;
}
Hope this helps.
There are at least three ways to do this:
I think Watin provides a tablehandler / tablecontroller related methods using which you can retrieve this information. You might want to search on that topic if you want to take this approach.
Using Xpath query (XML). Since you have the id of the table, you can use a XPath query to reach the node where your header is and verify that using a static string "Build ID" in your code. Same with the other pieces of information.
Regex - Using Regular Expressions, you can check if that text exists on the control / page.
If you view the source of your page, you will know the pattern that you should look for on the page. In fact, a simple Assert.AreEqual(true, new Regex("Build ID")Match.Success) should do the trick. However, this is a check that is purely done to see if the text exists on the page. You will not be looking at anything beyond that. Also, if you have multiple occurrences of the text then you should be considering the array of matches you get before you say, "yep, found it".
Note: You may have to checkout the syntax for using a Regex. The above information is just an abstract of what it would look like.
Cheers.