Current scenario:
Using cfmail tag with query for example.
<cfmail
query="qName"
to="#tomailvar#"
from="#frommailvar#>"
subject="#subjectvar#"
type="html"
server="smtp.sendgrid.net"
timeout="360"
username="#myuservar#"
password="#mypwdvar#"
>
how can i do threading in cfmail tag or current code?
I have client they send almost 40k in one shoot some time more.
I gave multiple accounts to my client, some time they simultaneous two users or three users sends 40k + 40k+ emails.
Is there a way i can count messages in spooler folder and verify with my total count of query ?
what is the right way to handle this much emails?
Which version of ColdFusion are you using? I'm surprised that you aren't encountering timeout issues. Since ColdFusion 6, we've been saving the HTML, TEXT and email list to a separate database and then have a background task loop over the data and send it in smaller batches.
Have you considered using a Transactional Email Service? We recently switched from Mandrill (because they're rolling it into MailChimp) to SparkPost (Free tier = 100,000 messages/mo). This type of service would provide you with the best stats & bounce/read/click detection (and sending 40k messages would take about ~2 seconds using CFHTTP.) You could also incorporate using "tags" for your accounts that are sending so you can keep track or set up separate accounts for each client. (NOTE: If you use SMTP API, be sure to set up unique DNS CNAMES for each SMTP customer or ColdFusion may use an existing authenticated connection and send messages using the wrong SMTP account.)
In addition to SMTP connections (one message at time), REST APIs are available which allow you to generate & post a single JSON packet containing the HTML/TEXT templates, email list, substitution parameters, campaign id, tags, optional headers, etc. I prefer sending through these services because it doesn't result in my IPs being blacklisted or incur delivery delays of time-sensitive messages.
Here's a comparison chart of various transactional email providers.
http://socialcompare.com/en/comparison/transactional-emailing-providers-mailjet-sendgrid-critsend
Here's a sample REST API call using SparkPost. (I'm providing this because almost no third-party services provide code samples for CFML.)
<cfscript>
APIKey = "abc123";
/* Generate Message Object */
messageObject = {
"campaign_id" = "Test1234",
"options" = {
"open_tracking" = Javacast("boolean", true),
"click_tracking" = Javacast("boolean", true)
},
"recipients" = [
{"address" = {"email" = "user1#email.com", "name"="User 1 Name"}, "substitution_data"= {"fullname"="Mr. User 1"}},
{"address" = {"email" = "user2#email.com", "name"="User 2 Name"}, "substitution_data"= {"fullname"="Ms. User 2"}},
],
"content" = {
"tags" = ["testing", "demo"],
"from" = {"email"="my#email.com", "name"="My Name"},
"subject" = "Oh hey {{fullname}} (#Request.DateTimeFormat(StartTime,'m/d/yyyy')#)",
"html" = "<b>Testing REST API {{fullname}}</b><br><br>Sending email using a transactional email service.",
"text" = "Testing REST API {{fullname}} - Sending email using a transactional email service.",
"headers" = {
"X-CUSTOM-HEADER" = "foo bar"
}
}
};
/* Recommend using JSONUtil for proper casting of boolean values */
JSONUtil = CreateObject("component","JSONUtil");
MessageJSON = JSONUtil.Serialize(var=messageObject, strictMapping=true);
</cfscript>
<cfhttp url="https://api.sparkpost.com/api/v1/transmission" method="post" result="httpResp" timeout="60" getasbinary="never">
<cfhttpparam type="header" name="Content-Type" value="application/json">
<cfhttpparam type="header" name="Authorization" value="#APIKey#">
<cfhttpparam type="body" value="#MessageJSON#">
</cfhttp>
<CFDUMP VAR="#httpResp#">
Related
I'm running a java XPage rest api that operates on the rooms & resource reservation database. It's executed by a single designated user which has full access to the database.
What I want to do, is to re-schedule someone's else meeting directly via the database. It works when I view it in the database, the meeting is updated successfully, however in the chair's notes client calendar, the meeting still appears as it was, despite receiving an "Accepted: " e-mail with new meeting date (I think it should be "Rescheduled:" though..)
Here's my code that creates a response document & sends it:
DateTime dt_startDateUTC = session.createDateTime(dtStart);
DateTime dt_endDateUTC = session.createDateTime(dtEnd);
Document docNew = reDatabase.createDocument(); // response doc
docAppointment.copyAllItems(docNew, true); // copy items from origianl doc
docNew.replaceItemValue("NoticeType", "U"); // update notice
docNew.replaceItemValue("CalendarDateTime", dt_startDateUTC);
docNew.replaceItemValue("SequenceNum", docAppointment.getItemValueInteger("SequenceNum") + 1); // bump SequenceNum
docNew.replaceItemValue("RmNameUpdated", "");
docNew.replaceItemValue("ResNameUpdated", "");
docNew.replaceItemValue("$RnRVersion", "2");
docNew.replaceItemValue("$CSVersion", "2");
docNew.replaceItemValue("Form", "Notice");
docNew.replaceItemValue("$NoPurge", dt_endDateUTC.getLocalTime());
docNew.replaceItemValue("StartDateTime", dt_startDateUTC);
docNew.replaceItemValue("StartDate", dt_startDateUTC);
docNew.replaceItemValue("StartTime", dt_startDateUTC);
docNew.replaceItemValue("RepeatInstanceDates", dt_startDateUTC);
docNew.replaceItemValue("EndDateTime", dt_endDateUTC);
docNew.replaceItemValue("EndDate", dt_endDateUTC);
docNew.replaceItemValue("EndTime", dt_endDateUTC);
docNew.removeItem("ReserveDate");
docNew.removeItem("step");
docNew.removeItem("$BusyPriority");
docNew.removeItem("$BusyName");
docNew.replaceItemValue("wgcIGNORE", "1");
docNew.replaceItemValue("$CSFlags", "w"); // taken from c&s workflow schema
docNew.replaceItemValue("Form", "Notice");
docNew.replaceItemValue("_ViewIcon", "33");
docNew.makeResponse(docAppointment);
docNew.send();
docNew.save();
docNew.recycle();
In my server log I see:
Router: Message 00325BD6, 0027FEE7 delivered to Room 1/Organization
Router: Message 00325C92 delivered to testuser/Organization
In my user's notes client I can see a new received mail from Room 1 titled "Accepted: Meeting subject" and when I enter it, the dates are correct (rescheduled), but when I click "Open meeting" the meeting still has old dates.
Am I doing something wrong? How can I enforce an update of that meeting? I already tried many different ways but without luck. I cannot modify user's calendar directly because I'd need to assign access to every user's mail database and that wouldn't be secure.
in a Sandbox environment nlapiSendEmail (defined inside a suitelet) returns SSS_AUTHOR_MUST_BE_EMPLOYEE even when the sender id is correct
My distribution is Kilimanjaro, with SuiteScript 1.0. I have an administrator role, when calling nlapiSenEmail() directly from the backend model with my employee id, the email was sent to my employee profile, but not to the specified email, which is really a company distribution list. Even when I did not specify the logged customer email, a copy was sent to the logged customer email, a gmail account. The backend model operates only for the MyAccount application. It's worth noting that in this scenario nlapiSendEmail() return value was undefined. In my experience, Netsuite is really ambiguous in its behavior returning values or just functioning in an expected way, due to the "execution context". So, with the same data I put my call inside a suitelet, and now I am having the return SSS_AUTHOR_MUST_BE_EMPLOYEE.
function sendEmailWithAPI(request, response)
{
var senderId = request.getParameter('senderId');
var to = request.getParameter('emailTo');
var subject = request.getParameter('subject');
var body = request.getParameter('body');
var cc = request.getParameter('emailCC');
var result = {success:false, errorInfo:''};
try
{
var sendingResult = nlapiSendEmail(senderId, to, subject, body, cc);
result.success = true;
}
catch (errorOnMailSending)
{
result.returnValue = sendingResult;
result.errorInfo = errorOnMailSending.details;
}
response.write(JSON.stringify(result));
}
What is the record type of the senderId? NetSuite only accepts Employee records as sender of script generated emails. Also in Sandbox accounts, the emails are re-routed to the logged in user, specific list, or not at all. This is actually based on the Company preference in your Sandbox account. The reason for this is Sandbox is usually used for testing and you don't want to send test emails to actual customers.
In the end the "problem" was that I was just working in the Sandbox, as I prepared a snippet to test email sending in production everything went right. In the sandbox you can still send emails specifying a list at the subtab "Email options"
with the option "SEND EMAIL TO (SEPARATE ADDRESSES WITH COMMAS)"
this is located at Setup > Company > Email Preferences.
Basically my ‘Maintopic’ topic receives three types of xml files (‘TEST’,’DEV’,’PROD’).
‘MainSubscription’ subscribes to that topic and now based on the XML file type, I need to route the XML files to:
Respective topics (child topics).
See the below message flow.
Maintopic --à MainSubscription’ (Filter on xml node type)-- > child topic 1 ( xml node type=’TEST’)
child topic 2 ( xml node type=’DEV’)
child topic 3 ( xml node type=’PROD)
I can add a subscription to the ‘Maintopic’, but where can I define all the filter logic for routing the file?
I am new to Azure cloud, how can I do this? I don't even know where to start.
Service Bus supports three filter conditions:
Boolean filters - The TrueFilter and FalseFilter either cause all arriving messages (true) or none of the arriving messages (false) to be selected for the subscription.
SQL Filters - A SqlFilter holds a SQL-like conditional expression that is evaluated in the broker against the arriving messages' user-defined properties and system properties.
Correlation Filters - A CorrelationFilter holds a set of conditions that are matched against one or more of an arriving message's user and system properties.
You must create a filtered subscription which will only receive messages you are interested in.
A filter can be based on any properties of the BrokeredMessage, except the body, since that would require every message to be desterilized in order to be handed on to the correct subscriptions. You can use sql filter.
An example of sql filter is below –
if (!namespaceManager.SubscriptionExists(topicName, filteredSubName1))
{
namespaceManager.CreateSubscription(topicName, filteredSubName1, new SqlFilter("From LIKE '%Smith'"));
}
You don’t send your messages directly to a subscription, you send them to the topic, and that will forward them to all the relevant subscriptions based on their filters. Below is the example -
var message1 = new BrokeredMessage("Second message");
message1.Properties["From"] = "Alan Smith";
var client = TopicClient.CreateFromConnectionString(connectionString, topicName);
client.Send(message1);
Below is how you receive message –
var subClient = SubscriptionClient.CreateFromConnectionString(connectionString, topicName, subscriptionName);
var received = subClient.ReceiveBatch(10, TimeSpan.FromSeconds(5));
foreach (var message in received)
{
Console.WriteLine("{0} '{1}' Label: '{2}' From: '{3}'",
subscriptionName,
message.GetBody<string>(),
message.Label,
message.Properties["From"]);
}
I'm trying to search the existing Customers and return the CustomerID if it exists. This is the code I'm using which works:
var CustomerToFind = new Customer
{
MainContact = new Contact
{
Email = new StringSearch { Value = emailIn }
}
};
var sw = new Stopwatch();
sw.Start();
//see if any results
var result = (Customer)soapClient.Get(CustomerToFind);
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds);
However, I've finding it appears extremely slow to the point of being unusable. For example on the DEMO dataset, on my i7-6700k # 4GHz with 24gb ram and SSD running SQL Server 2016 Developer Edition locally a simple email search takes between 3-4seconds. However on my production dataset with 10k Customer records, it takes over 60 seconds and times out.
Is this typical using Contract based soap? Screen based soap seems much faster and almost instant. If I perform a SQL select on the database tables in Microsoft Management Studio I can also return the result instantly.
Is there a better quick way to query if a Customer with email address = "test#test.com" exists and return the Customer ID?
Try using GetList instead of Get. It's better suited for "search for smth" scenarios.
When using GetList, depending on which endpoint you're using, there are two more optimizations. In Default/5.30.001 endpoint there's a second parameter to GetList which you should set to false. In Default/6.00.001 endpoint there's no second parameter but there is additional property in the entity itself, called ReturnBehavior. Either set it to OnlySpecified and then add *Return to required fields, like this:
var CustomerToFind = new Customer
{
ReturnBehavior = ReturnBehavior.OnlySpecified,
CustomerID = new StringReturn(),
MainContact = new Contact
{
Email = new StringSearch { Value = emailIn }
}
};
or set it to OnlySystem and then use ID on returned entity to request the full entity.
My Kentico server is unable to send e-mails, so I have to transform my e-mail using MacroResolver, but send it using some other way.
var clients = new List<Client>();
var macroResolver = MacroResolver.GetInstance();
macroResolver.AddDynamicParameter("clients", clients);
var emailMessage = new EmailMessage {
From = "someone#somewhere.com",
Recipients = "otherone#somewhere.com",
Subject = "Whatever"
};
var template = EmailTemplateProvider.GetEmailTemplate(templateName, siteName);
EmailSender.SendEmailWithTemplateText(siteName, emailMessage, template, macroResolver, true);
In other words, I would like to use Kentico just as a Template Engine. Is there anyway to achieve this?
What SendEmailWithTemplateText method basically does is it fills empty fields of message by its equivalent from a template and resolve macro values in it. If you are only after message body, then you can create the email message by:
emailMessage.Body = macroResolver.ResolveMacros(emailMessage.Body);
emailMessage.PlainTextBody = macroResolver.ResolveMacros(emailMessage.PlainTextBody);
For most scenarios it's also better to tell the resolver to encode resolved values. You can do it by: resolver.EncodeResolvedValues = true;
Also you are passing whole 'clients' collection to the resolver. You'll probably need to take it one by one and generate emails in a loop.