TriggeredEmail error - contact [] does not have valid email id [msid:]

Hello, here is what I have setup:

  1. Members area as per WIX

  2. Tasks for each member with due dates

  3. TriggeredEmail set up to send emails to members with unfinished tasks.
    a) I have set up the email itself with a variable that lists a number of unfinished tasks in the email subject.
    b) I have set up events.js and aModule.jsw in the backend to allow me to test using a frontend button
    c) I added couple of console.log lines to help with debugging as well.

  4. I am getting an error that the contactId doesn’t have a valid email id (see below - first is the screenshot of my site log while the second one is the detailed error description)

“root”: {

“insertId”:“…CEfKH.NAO2I9iQVDRFQ2_u”
“timestamp”:“2021-11-30T19:26:29.130Z”

“labels”: { “siteUrl”:“https://www.pbjamplatform.com/
“revision”:“2824”
“namespace”:“Velo”
“tenantId”:“d23a919e-9f5e-4462-a8bd-257cd5eb9544”
“viewMode”:“Site”
}

“sourceLocation”: { “file”:“backend/events.js”
“line”:47
“column”:13
}

“operation”: { “id”:“1638300385.98085739101361”
“producer”:“backend”
}

“jsonPayload”: { “message”:"["Daily_Reminderes.js 55 “,“Contact [id=c80383cf-3272-44fa-9870-7290aa090422] does not have valid email [msid=d23a919e-9f5e-4462-a8bd-257cd5eb9544]”]”
}
“severity”:“INFO”
“receiveTimestamp”:“2021-11-30T19:26:31.001Z”
}

Any hints/thoughts on why the email is not getting retrieved based on contactId?

Check the email address of this contact and see if it’s valid.

Thanks JD! Yes, I checked and it is a valid address of yahoo.com domain.

Any other thoughts? @giri-zano , @yisrael-wix

@psaraph I don’t think there’s enough info in your description for us to figure it out.
Maybe you should contact Wix Support.

@jonatandor35 Thanks JD! Have done so… Here is what I attached to the ticket. Let me know if it brings any other thoughts/hints to your mind.

Having the same issue. Cannot even send the email to my own user ID (as an admin) which has a valid email.

Could this be something to do with the new Members API not behaving properly? It seems that the new API that is supposed to replaced the now-deprecated Users API have been running into a few issues .

When trying to retrieve the login email of a user, the new wix-members-backend API returns null for some reason, whereas the old wix-users-backend works just fine.

Here, the memberId is of a site admin.

import wixMembersBackend from 'wix-members-backend';
import wixUsersBackend from 'wix-users-backend';

const memberId = "123xyz-abcefg-xxxxx-xxxxx-xxxxxx";

/** New Members API */

/** @type   {wix_members_backend.Members.Member} */
const a = await wixMembersBackend.members.getMember(memberId);
console.log(a);             // {...}    the full Member object
console.log(a.loginEmail);  // null

/** Old Users API */

/** @type   {wix_users_backend.RetrievedUser} */
const b = await wixUsersBackend.getUser(memberId);
console.log(b);             // {...}    the full RetrievedUser object
console.log(b.loginEmail);  // example@email.com

The output shows that both APIs can fetch the user information but the loginEmail property for a is null, whereas the login email for b shows up correctly.

OK, got this one solved… thanks to WIX support. I have attached three files that are working for me along with the Triggered Email output and template. Good luck!

If you want to send emails based on VELO code (and not just based on form submission), here are the steps:

  1. Click on spanner icon (Automation) on the left side panel when you are in Editor X under Dev mode. Click on Triggered Emails to edit or create Triggered Email template. Note: Velo will generate a randomized name for new template, but you can edit it to make it more readable for you.

  2. In Triggered Email, add variables/graphics/text as you want. Variables are what you want to get from Velo code as part of “customization”. Note: Triggered Email variables will get only
    plain text from Velo code (if you are planning on getting Rich Text, no luck as of now)

  3. Click on {} icon (Code Files) on the left side panel when you are in Editor X under Dev mode

  4. Now build your files, namely, a) events.js, b) aModule.jsw and c)jobs.config

  5. Your events.js file will hold the VELO code that will build the email and content as per your criteria, for example, you can query your collection and decide to include only those items that have been modified in the last 7 days. Make sure to encapsulate your code as a function!

Go wild…whatever catches your fancy, write it up as javascript code! In my example, I used events.js to find open action items for my members, build links to dynamic pages where user can go and edit/update those actions, add a randomized hint from another collection and then pass all this custom content over to TriggeredEmail function (with specific email template ID and variables).

  1. Your aModule.jsw file should contain just a call to the function that you just built in events.js file. This will help you to call the code and execute it via frontend while you are debugging, which is what I used it for (You can also then trigger emails on demand as part of site admin tasks if needed)

  2. Your jobs.config file is the cron job file that will trigger the specified email/actions on certain time/day/date as needed. In my case, I set it for hourly while debugging and then for weekdays 0700 AM CST for live site.

Well, looks like I can’t attach files anymore! :frowning: But, here is the code for each file as individual posts… first one is events.js

//*******************
import wixData from ‘wix-data’ ;
import { triggeredEmails } from ‘wix-crm-backend’
var temp01 , temp02 , action01 , action02 , dd00 , dd01 , dd02 , ddtemp , link01 , link02 , link03 , DailyBiteHeading , DailyBiteDetails

export async function FindSMART ( ) {
// Access E4_ACTIONS
// Find all open actions i.e. those that are not completed or voided
wixData . query ( “E4_ACTIONS” )
. ne ( “status” , “Completed” )
. ne ( “status” , “Void” )
. ascending ( “dueDate” )
. eq ( “responsible” , "*********@gmail.com" ) // Debugging filter to avoid sending emails to all members
. find ()
. then (( CurrentActions )=>{
let FoundRecord = CurrentActions . items [ 0 ]
let contactId = FoundRecord . _owner
ddtemp = FoundRecord . dueDate
dd00 = ddtemp . toDateString ()
link01 = “https://www.//" + FoundRecord . _id
console . log ( "events.js 42 Found " , CurrentActions . items . length , " current actions for user " , contactId )
if ( CurrentActions . items . length > 1 ){ temp01 = CurrentActions . items [ 1 ]; action01 = temp01 . action ; ddtemp = temp01 . dueDate ; dd01 = ddtemp . toDateString (); link02 = "https://www.
//” + temp01 . _id }
else ( action01 = “NA” , link02 = “” )
if ( CurrentActions . items . length > 2 ){ temp02 = CurrentActions . items [ 2 ]; action02 = temp02 . action ; ddtemp = temp02 . dueDate ; dd02 = ddtemp . toDateString (); link03 = “https://www.******//” + temp02 . _id }
else ( action02 = “NA” , link03 = “” )
wixData . insert ( ‘TR003_ScheduledJobsTracking’ ,{ “currentActions” : CurrentActions . items . length , “Member ID” : contactId , “ActionOne” : FoundRecord . action + dd00 , “ActionTwo” : action01 + dd01 , “ActionThree” : action02 + dd02 })
console . log ( "events.js 51 Link01 " , link01 , " Link02 " , link02 , " Link03 " , link03 )
//Find a random daily bite and assign it to DailyHint
let BiteNum = Math . round ( Math . random ()
60 + 1 )
console . log ( "51 DailyBite Number = " , BiteNum )
wixData . query ( “LIST_DAILY_HINTS” )
. eq ( ‘number’ , BiteNum )
. find ()
. then (( Bite )=>{
DailyBiteHeading = Bite . items [ 0 ]. dailyBite
DailyBiteDetails = Bite . items [ 0 ]. description
console . log ( "57 DailyBiteHeading = " , DailyBiteHeading , " DailyBiteDetails = " , DailyBiteDetails )
triggeredEmails . emailMember ( ‘SMARTstepReminder’ , contactId , {
variables : {
CountOpen : CurrentActions . items . length ,
SMARTstep01 : FoundRecord . action + " ::: DUE DATE => " + dd00 ,
SMARTstep02 : action01 + " ::: DUE DATE => " + dd01 ,
SMARTstep03 : action02 + " ::: DUE DATE => " + dd02 ,
Link01 : link01 ,
Link02 : link02 ,
Link03 : link03 ,
DailyHintHeading : DailyBiteHeading ,
DailyHintDescription : DailyBiteDetails ,
}
})
. then ( ( success ) => {
console . log ( “events.js 73 Triggered email sent” );
} )
. catch ( ( err ) => {
console . log ( "events.js 76 " , err );
} );
return ( CurrentActions . items . length )
})
})
. catch (( err )=>{ console . log ( err )})
}

Here is aModule.jsw

import { FindSMART } from ‘backend/events’

export function ReminderEmail ( ){
FindSMART ()
}

And here is the jobs.config with an hourly call to ReminderEmail function

{
“jobs” : [{
“functionLocation” : “/aModule.jsw” ,
“functionName” : “ReminderEmail” ,
“description” : “Daily Reminder on SMART-steps” ,
“executionConfig” : {
“cronExpression” : “0 * * * *”
}
}]
},