Communities @Mention email notifications failure and activity feed crashes DescriptionWhen users @mention other users in Communities (questions, answers, comments, blogs, events), two critical failures occur: 1. Email notifications are not sent to the mentioned user 2. Activity feed crashes when attempting to render the mention on the Community home pageSteps to Reproduce Prerequisites: - Communities configured - Two test users with forum access Steps: 1. Create content(Question, Answer, Blog, Comment, Reply etc) with @mention in rich text editor Log in as Test User 1Navigate to any Community forumCreate a question, blog, or commentType "@" and select Test User 2 from the dropdownSubmit the content 2.Verify notification failure Check Test User 2's email inbox in sys_email tableExpected: No email notification received 3. Verify activity feed crash Log in as Test User 2Navigate to Community home pageExpected: Activity feed widget crashes or fails to render the mentionWorkaroundRoot Cause The TinyMCE rich text editor's schema does not include sn-mention as a valid element with its required attributes. As a result, when content is saved, the table attribute is stripped from the <sn-mention> tag. Expected format: <sn-mention table="live_profile" sysid="<user_sys_id>" class="class_name">@User Name</sn-mention> Actual output (missing table attribute): <sn-mention sysid="<user_sys_id>" class="class_name">@User Name</sn-mention> The missing table attribute causes downstream failures in both the notification system and the activity feed rendering on the client side. Workaround This workaround has two parts: - Part A — Fix the TinyMCE editor configuration so new records are created correctly - Part B — Run a fix script to repair existing impacted records Critical Note: Always test in a sub-production environment first. Apply both Part A and Part B in your lower environment, perform thorough testing, and validate all @mention functionality works as expected before applying to production. Part A: Fix TinyMCE Editor Configuration (for new records) 1. Navigate to: <instance_URL>/sp_angular_provider.do?sys_id=237eaa563b00320037556b4ee3efc482 2. In the client script, find the function named setup 3. The existing code looks like this: setup: function(ed) { ed.on('init', function() { var editorContainer = thisEditor.getContainer(); if (editorContainer) { editorContainer.style.minHeight = height + getAdditionalHeights() + 'px'; } }); 4. Add the sn-mention valid elements registration inside ed.on('init', ...) as shown below: setup: function(ed) { ed.on('init', function() { var editorContainer = thisEditor.getContainer(); if (editorContainer) { editorContainer.style.minHeight = height + getAdditionalHeights() + 'px'; } // Workaround: Register sn-mention as a valid element so TinyMCE // Add the below code if (ed.schema) { ed.schema.addValidElements('sn-mention[class|sysid|table]'); } //Till Here }); 5. Save the record. This ensures that any new @mention records will retain the table attribute and work correctly. All community users should clear their browser cache or re-login to ensure the TinyMCE fix is applied when creating new @mentions. Part B: Fix Script Guide for Existing Records For existing records that are already impacted, a background script must be run to add the missing table attribute back to the <sn-mention> tags. Affected Tables The sn_actsub_activity.object_name field indicates which table holds the content record. There are 5 possible tables, each with a specific field containing the rich text: TableContent Fieldkb_social_qa_questionquestion_detailskb_social_qa_answeranswerkb_social_qa_commentcommentsn_communities_blogdescriptionsn_communities_eventdescription Steps to Write the Fix Script Step 1 — Query the activity records Query sn_actsub_activity with: - verb = mentioned - Optionally filter by sys_created_on to limit scope (e.g., records created after a specific date) Step 2 — Identify the target table and field For each activity record: - Read the object_name field — this contains the table name (e.g., kb_social_qa_comment) - Use the mapping above to determine which content field to fix - If object_name doesn't match any of the 5 tables skip the record and log it for investigation as it may indicate an unsupported content type. Step 3 — Fetch the content record - Use the object_id from the activity record to query the target table identified in Step 2 - Read the content field value (e.g., comment for kb_social_qa_comment, description for sn_communities_blog) - If the content doesn't contain sn-mention, skip the record Step 4 — Find and fix sn-mention tags - Parse the HTML content for all <sn-mention> tags - For each tag, check if the table attribute is present - If missing, add table="live_profile" to the tag attributes Step 5 — Validate before updating Before updating, verify the only change made is the addition of table="live_profile": - Take the updated content and remove all occurrences of table="live_profile" - Compare with the original content — they should be identical - If they differ, do not update — log the record for manual review instead Step 6 — Update the record - Set the content field on the target record with the fixed HTML - Call update() to save Step 7 — Review logs After execution, review: - Total records processed - Records updated per table - Any records that failed validation (these need manual review) Important Notes - Always test in a sub-production instance first before running in production - Scope the query using a date filter on sys_created_on to limit the number of records processed - Validation is critical — the Step 5 check ensures no unintended modifications are made to the content - Records that fail validation should be reviewed manually as they may have other HTML inconsistencies Before (impacted content): <p>Hey <sn-mention class="sn-mention" sysid="actual_sys_id_from_table">@John Smith</sn-mention> can you take a look at this?</p> After (fixed content): <p>Hey <sn-mention table="live_profile" class="sn-mention" sysid="actual_sys_id_from_table">@John Smith</sn-mention> can you take a look at this?</p> Note: The only difference is the addition of table="live_profile". No other content is modified.Here is a sample script that the customer can use as a reference for writing their own script to correct the data. (function() { var contentUpdateCount = 0; var processedCount = 0; var skippedCount = 0; var validationFailedIds = []; // Mapping of table name (from object_name) to the field that holds rich text content var TABLE_FIELD_MAP = { 'kb_social_qa_question': 'question_details', 'kb_social_qa_answer': 'answer', 'kb_social_qa_comment': 'comment', 'sn_communities_blog': 'description', 'sn_communities_event': 'description' }; // Query sn_actsub_activity records var grActivity = new GlideRecord('sn_actsub_activity'); grActivity.addEncodedQuery("verb=mentioned"); grActivity.query(); gs.info('Processing sn_actsub_activity records (verb=mentioned)...'); gs.info('Total records to process: ' + grActivity.getRowCount()); while (grActivity.next()) { processedCount++; var objectId = grActivity.getValue('object_id') || ''; var objectName = grActivity.getValue('object_name') || ''; if (!objectId || !objectName) { skippedCount++; continue; } // Determine the content field from the object_name (table name) var contentField = TABLE_FIELD_MAP[objectName]; if (!contentField) { skippedCount++; continue; } // Query the target table using object_id var grRecord = new GlideRecord(objectName); if (!grRecord.get(objectId)) { skippedCount++; continue; } var content = grRecord.getValue(contentField) || ''; if (!content || content.indexOf('sn-mention') === -1) { skippedCount++; continue; } var modified = false; // Regular expression to find sn-mention tags // Matches: <sn-mention attributes>content</sn-mention> var mentionRegex = /<sn-mention([^>]*)>([^<]*)<\/sn-mention>/gi; var updatedContent = content; var match; // Reset regex lastIndex mentionRegex.lastIndex = 0; while ((match = mentionRegex.exec(content)) !== null) { var attributes = match[1]; var mentionContent = match[2]; var fullTag = match[0]; // Check if table attribute exists var hasTable = /table=/i.test(attributes); if (!hasTable) { // Simply add table="live_profile" to existing attributes var newAttributes = ' table="live_profile"' + attributes; var newTag = '<sn-mention' + newAttributes + '>' + mentionContent + '</sn-mention>'; updatedContent = updatedContent.replace(fullTag, newTag); modified = true; gs.info('Fixed sn-mention tag in ' + objectName + '.' + contentField + ': ' + objectId + ' - Added table attribute'); } } // Update the target record's content field if modified if (modified) { // Validation: Verify the only difference is the addition of table="live_profile" var contentWithoutTable = updatedContent.replace(/ table="live_profile"/g, ''); if (contentWithoutTable === content) { // Safe to update - only table attribute was added grRecord.setValue(contentField, updatedContent); grRecord.update(); contentUpdateCount++; gs.info('Updated ' + objectName + ': ' + objectId + ' - Fixed sn-mention tags in field: ' + contentField); } else { // Unexpected difference detected - skip update and log for manual review validationFailedIds.push(objectName + ':' + objectId); gs.warn('VALIDATION FAILED for ' + objectName + ': ' + objectId + ' - Unexpected changes detected. Skipping update for manual review.'); skippedCount++; } } } gs.info('===== Fix Script Completed ====='); gs.info('Processed sn_actsub_activity records: ' + processedCount); gs.info('Skipped records (no object_id, unsupported table, or no mentions): ' + skippedCount); gs.info('Updated content records across tables: ' + contentUpdateCount); gs.info('Validation failed (needs manual review): ' + validationFailedIds.length); if (validationFailedIds.length > 0) { gs.info('===== Records requiring manual review (table:sys_id) ====='); for (var i = 0; i < validationFailedIds.length; i++) { gs.info(validationFailedIds[i]); } } gs.info('================================'); })(); Related Problem: PRB2000648