0

emailing list of contacts not changing the firstname in list

I have done a script to send an email to all valid contacts to update the prices. It all works fine except that I have an issue

in that the contact first name is only picking up the name of the record that I am on when I fire the script from and applying that name to all the emails html body letter

instead of changing it to each users name - FirstName ?

any suggestion?

Here is full script

"-----------------------------------------------------------------------------------";
"This code selects contacts where a Yes/No field (Send Email) is set to yes and GDPR = 1 (Opted In)";
"Then it loops through the records sending an email and re-setting the 'Send Email' flag to no";
"-----------------------------------------------------------------------------------";
for recipient in select Customers where 'GDPR Status' = 1 and 'Send Email' do
let thisBody := first((select SystemFile).Letter2);
let myEmail := userEmail();
let xFirst := FirstName;
let myAtt := first(files(record(SystemFile,1)));
thisBody := replace(thisBody, "{FirstName}", xFirst);
sendEmail({
from: myEmail,
to: recipient.Email,
subject: "Cusromer Price List Update",
text: "New updated price lits for your files",
html: thisBody,
attachments: myAtt
});
recipient.('Send Email' := 0)
end

20 replies

null
    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    ignore the text type in subject line !

    • Ninox partner
    • RoSoft_Steven.1
    • 3 yrs ago
    • Reported - view

    Change to:

    let xFirst := recipient.FirstName

    ....

    Steven

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    Styeven

    I can't believe I missed that!

    Sometimes you can't see the wodd for the trees!

    Thank you for the casting the fresh pair of eyes over the script.

    One day and I do mean one day I will manage to help you in return !!!

    kind regards

    Mel 

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    Steven

    I want to limit the above script to a batch of 75 records at a time

    what's the best approach to achive this?

    I've tried couple of things like example further below but whilst the script is accepted it ignores it at run time.

    I'm guessing the condition of select, where and do it literally working through all files

    let myC := 1

    then adding 

    for recipient in select Customers where 'GDPR Status' = 1 and 'Send Email' and myC <75 do

    the adding further down

    let myC := myC +1 etc

    • Ninox partner
    • RoSoft_Steven.1
    • 3 yrs ago
    • Reported - view

    Off the cuff....

    Try this: ('Emailsend' is an extra yes/no field if you haven't got one in your table Customers)

    let sendmails := select Customers where 'GDPR Status' = 1 and 'Send Email' and Emailsend = false;
    let myCount := if cnt(sendmails) > 75 then 75 else cnt(sendmails);
    for i in range (0,myCount) do
    let thisBody := first((select SystemFile).Letter2);
    let myEmail := userEmail();
    let xFirst := item(sendmails,i).FirstName;
    let myAtt := first(files(record(SystemFile,1)));
    thisBody := replace(thisBody, "{FirstName}", xFirst);
    item(sendmails,i).Emailsend := true;
    sendEmail({
    from: myEmail,
    to: recipient.Email,
    subject: "Cusromer Price List Update",
    text: "New updated price lits for your files",
    html: thisBody,
    attachments: myAtt
    });
    recipient.('Send Email' := 0)
    end

    It might need some tweaking, let me know if it works....
    let xFirst := record(Customers,item(sendmails,i)).FirstName; (if the above doesn't work change this)
    record(Customers,item(sendmails,i)).Emailsend := true; (if the above doesn't work change this)

    Steven

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    Hi Steven

    Thank you - I haven't tried the other options at the botton co I can't get past an error

    let sendmails := select Customers where 'GDPR Status' = 1 and 'Send Email' and Emailsend = false;
    let myCount := if cnt(sendmails) > 75 then 75 else cnt(sendmails);
    for i in range (0, myCount) do

    this line in bold is giving me a field not fount error (col 26)

    seems to think that myCount is a field and not a variable as defined in line 2

    My 'Send Email' Field is a yes/no flag to add extra control over the gdpr status (so if both are true send the email out) then set send email to false

    So is your extra Emailsend (yes/no) field needed ?

    cheers Mel

    • Fred
    • 3 yrs ago
    • Reported - view

    Try:

    let myCount := if cnt(sendmails) > 75 then 75 else cnt(sendmails) end; <--you need an end to close the if statement.

    • Ninox partner
    • RoSoft_Steven.1
    • 3 yrs ago
    • Reported - view

    Thanks Fred, didn't see that.

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    Fred/Steven

    This is really getting there !

    There is just a small issue in that it was now giving me an error in as shown the bold lines below as they are no longer recognised

    ie was previous refering to by following line (recipient variable)

    for recipient in select Customers where 'GDPR Status' = 1 and 'Send Email' do

     

    ah - I though maybe then I need to replace recipient for sendmails?

    tried this all it works BUT if grabs every email due to go and sneds it to every one - so say there is a batch of 6 emails - it sends 6 emails with each name added to the send to address box 

    so technically 36 emails were send out and each contact got 6 emails all saying the same with all contacts visable in the sent to box

    so clearly that is not right - although I am not sure how to correct this ? Somehow i still need to define recipient and not have the loop?

     

    Screenshot 2021-10-01 at 17.58.58 it send this 6 times to each group!

     

    let sendmails := (select Customers where 'GDPR Status' = 1 and 'Send Email' and EmailSend = true);
    let myCount := if cnt(sendmails) > 75 then 75 else cnt(sendmails) end;
    for i in range(0, myCount) do
    let thisBody := first((select SystemFile).FollowUpLetter);
    let myEmail := userEmail();
    let xFirst := item(sendmails, i).FirstName;
    let myAtt := first(files(record(SystemFile,1)));
    thisBody := replace(thisBody, "{FirstName}", xFirst);
    item(sendmails, i).(EmailSend := true);
    sendEmail({
    from: myEmail,
    to: recipient.Email,
    subject: "Thank you for past purchases from 118Printgroup, but did you know we print much more?",
    text: "from 118 Printgroup",
    html: thisBody,
    attachments: myAtt
    });
    recipient.('Send Email' := 0)
    end

    • Fred
    • 3 yrs ago
    • Reported - view

    Hi Mel -

    1) what happened to the recipient variable? if you changed it to sendemails then you need to replace all instances of recipient.

     

    2) in the "to" section, I think you might need to so something like you for xFirst.

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    Fred

    I used stevens last example. He removed the recipient from the definition and left it in further down - so i did the same.

    I've stripped the code back to remove the attachments etc that I know works (I'll add code back later) just to show show where I am (i've changed the recipients variable to myPost (just for abit of clarity).

    let myPost := (select Customers where 'GDPR Status' = 1 and EmailSend = true); This line works (if there are 6 value in the list it selects all 6)

    let myCount := if cnt(myPost) > 3 then 3 else cnt(myPost) end; (this definately selects only 3 emails to send out)
    for i in range(0, myCount) do
    let myEmail := userEmail();
    let xFirst := item(myPost, i).FirstName;
    item(myPost, i).(EmailSend := false);
    sendEmail({
    all this section works - so no issue here
    });
    myPost.(EmailSend := 0)
    end

    but what actually happens is that 3 emails are sent but all 6 vaild emails are attached to each of the 3 emails

    so in this case each email copy to 6 users - giving 18 emails gone out

    I'm confused now !!!!

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    if i move this line from the middle and put it at the end

    item(myPost, i).(EmailSend := false)

     

    then the script correctly detects 3 email to go out and sets the correct qty of the EmailSend flag back to false instead of all 6 in the list.

    but the actual email going out then does not work at all :-(

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    So in essence !!

    The counter is picking up the first email then adding all the valid emails into that first email then moving onto counter 2 and doing the the same

    I'm struggling to see how I can break down the select query line so that it only get one email at at time. Obviously without the counter lines added -  The script ran fine.

    Albiet - I would have to manually run down the table view, setting 'EmailSend' to true for the amount I want to go out in a batch.

    But given that I have over 600k customer records and to then manually set 75 at a time would be quite an undertaking!

    • John_Halls
    • 3 yrs ago
    • Reported - view

    Hi Mel

     

    You don't need to add any counter lines. Take your select statement and then scope this to the first 75 lines

     

    let a:= select Customers where 'GDPR Status' = 1 and 'Send Email';

    for recipient in slice(a, 0, 75) do

     

    The rest of your initial script can stay the same, especially as 'Send Email' is set to 0 as this runs, so next time the script will run using the next 75 customers.

     

    Regards John

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    Hi John

    YAY !! - That works !!! 

    For testing - I changed the 75 to a batch of 3. Fired it off twice - It did exactly what you said it would and effectively walks down the list.

    That's great because across all my customers list. I can set a sensible batch per day and simply fire the button off when I'm ready.

    Alsi I can now set the table view to sort descending on sendemail and i wil always know where i am.

    Once the list is walked through I can do a table update with a contant value to reset sendmail. 

    Thanks for this :-)

    What does slice do?

    Fred/Steven

    I would still like to get my head around the counter/select though please to see if a solution is still possible this way.

    I need to understand how the counter was trying to count but then including all the email in the sedning then mnovining onto count 2 then doing the same.

    I really appreciate the time and support you guys give me! - THANKYOU! 

    Kind regards

    Mel

    • John_Halls
    • 3 yrs ago
    • Reported - view

    That's great Mel

     

    slice gives you a subset of an array

    slice(array, start, end)

    Arrays start counting from 0 ( so 0 is the first element of the array) and the start is inclusive but I think end is exclusive (so 75 still gives you 75 elements even though it started at 0)

     

    Regards John

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    ah John

    Got it - slice is a method used with strings to return all characters after a start position or between 2 points

    that's a new one learned !!

    • Ninox partner
    • RoSoft_Steven.1
    • 3 yrs ago
    • Reported - view

    In essence, you get an array with all the Id's of the table when you use a select statement e.g. [1,5,100,155,255,688,697,789,790,791,792]

    So we have now an array of 11 values. Suppose you wanted to send 12 email at a time.

    with the slice function we divide the found Id in slices of 12. cnt(array) tells there is only 11 so the counter should be 11 and not 12:

    myCount := if cnt(array)>12 then 12 else cnt(array) end

    now sending emails to the array list (with the function item() selecting the Id's of the array:)

    The first item of an array has position 0 (zero) and the last position has variable: myCount - 1 or like John use it : slice(myCount,0,11) With slice, he shortens the array to 12.

    now we say: for i in range(0,myCount-1) do is telling to select the first Id untill the last Id (contained in i) which is in the list of the array , send an email with i.Emailadres

    If you put this code in a button, the more you pusch the button, the less records would be selected in your select-statement if you have a field like 'EmailSend' if the email was already send.

    Hope this explains the code a little more.

    Steven

    • Fred
    • 3 yrs ago
    • Reported - view

    My guess, since I don't have a db to try this one. Is that in the counter situation, you are not telling the for statement to use a specific email address. I think I asked earlier about the to section of the email. It basically said:

     

    to: recipient.Email

     

    I think you have to do something like:

     

    item(myPost, i).Email;

     

    Once you switched to a range you have lost all connection to any records. That is why John's method is better. Your last connection to your records is in your myPost variable. So you need to do what you did for FirstName, you have to pull the record Id from your MyPost and then get the email address of that record.

     

    Which I think your reporting say that this is exactly what it is doing. You said it found 6 records. Then it sent out 3 email to all 6 records. So your data set has 6 email addresses that Ninox adds to the to line and sends it out 3 times cause you limited the range from 0 - 3

     

    John's method keeps the reference to the record so you can use your basic code cause Ninox is only working on one record at a time.

     

    Hope this helps.

    • Mel_Charles
    • 3 yrs ago
    • Reported - view

    John/Fred/Steven

    Thank you for various explanations. That really helps !

    As stated before, I'm not a coder in any way but see it as a task to do in order to drive my business. That said I have progressed quite some way.

    This issue for me (and I guess many others!) is that I don't know - what I don't know!.

    Hope that makes sense so when faced with some problems. I can full state it in English how to work through the problem, but transfering that into code/script can be problematical when a) You have no model to base it on. B) You don't have the knowledge of all the scripts etc.

    As with most things it relys on experience gained with Practise, Understanding and Feedback.

    You guys help make that process easier ! - Thank you as ever :-)

    P.s Although I know I have the solution now. I'm going to carry on see if I can get the script working fully using the counter method.  

Content aside

  • 3 yrs agoLast active
  • 20Replies
  • 895Views