SQL query tested in SQL 4 CDS to fetch all emails removed by Microsoft in the issue 5352440 (Reference DV1121532).
WITH AuditData AS ( SELECT audit.objectid, audit.objectidname, -- We get the prevEmail from the shredded JSON data below json_attributes.oldValue AS 'prevEmail', contact.emailaddress1, audit.useridname, audit.createdon FROM audit INNER JOIN contact ON audit.objectid = contact.contactid -- Use CROSS APPLY to parse the JSON array for each row in the audit table CROSS APPLY OPENJSON(audit.changedata, '$.changedAttributes') WITH ( logicalName NVARCHAR(128) '$.logicalName', oldValue NVARCHAR(MAX) '$.oldValue' ) AS json_attributes WHERE audit.createdon >= '2025-07-20' AND audit.attributemask LIKE '%42%' AND audit.objectidtype = 'contact' AND (contact.emailaddress1 = '' OR contact.emailaddress1 IS NULL) -- Filter the shredded JSON to find only the email address change AND json_attributes.logicalName = 'emailaddress1' ), RankedAudits AS ( SELECT objectid AS 'contactId', objectidname AS 'contactName', prevEmail, emailaddress1 AS 'Email', useridname AS 'modifiedBy', createdon, ROW_NUMBER() OVER(PARTITION BY objectid ORDER BY createdon DESC) as 'rowNum' FROM AuditData ) SELECT contactId, contactName, prevEmail, Email, modifiedBy, createdon FROM RankedAudits WHERE prevEmail IS NOT NULL AND prevEmail != '' -- Also good to exclude empty strings AND rowNum = 1 ORDER BY createdon DESC;
This query can also be used after MS rolls out the mitigation solution, so any emails let behind will be retrieved.
It can takes a while to finish running, but it's a one-time job. So make sure that Stop query execution after is set to 0 in the Settings:

[Edit] Based on the previous query, I developed a new generic one to recover the emails erased from the contacts affected.
-- Step 1: Create a temporary table to store the results of your audit query. -- This isolates the data we need to work with. CREATE TABLE #EmailUpdates ( contactId UNIQUEIDENTIFIER, contactName NVARCHAR(255), prevEmail NVARCHAR(255), Email NVARCHAR(255), modifiedBy NVARCHAR(255), createdon DATETIME ); -- Step 2: Insert the data from your query into the temporary table. WITH AuditData AS ( SELECT audit.objectid, audit.objectidname, -- We get the prevEmail from the shredded JSON data below json_attributes.oldValue AS 'prevEmail', contact.emailaddress1, audit.useridname, audit.createdon FROM audit INNER JOIN contact ON audit.objectid = contact.contactid -- Use CROSS APPLY to parse the JSON array for each row in the audit table CROSS APPLY OPENJSON(audit.changedata, '$.changedAttributes') WITH ( logicalName NVARCHAR(128) '$.logicalName', oldValue NVARCHAR(MAX) '$.oldValue' ) AS json_attributes WHERE audit.createdon >= '2025-07-20' AND audit.attributemask LIKE '%42%' AND audit.objectidtype = 'contact' AND (contact.emailaddress1 = '' OR contact.emailaddress1 IS NULL) -- Filter the shredded JSON to find only the email address change AND json_attributes.logicalName = 'emailaddress1' ), RankedAudits AS ( SELECT objectid AS 'contactId', objectidname AS 'contactName', prevEmail, emailaddress1 AS 'Email', useridname AS 'modifiedBy', createdon, ROW_NUMBER() OVER(PARTITION BY objectid ORDER BY createdon DESC) as 'rowNum' FROM AuditData ) INSERT INTO #EmailUpdates (contactId, contactName, prevEmail, Email, modifiedBy, createdon) SELECT contactId, contactName, prevEmail, Email, modifiedBy, createdon FROM RankedAudits WHERE prevEmail IS NOT NULL AND prevEmail != '' -- Also good to exclude empty strings AND rowNum = 1; -- Step 3: Preview the changes. -- Run the SELECT statement below to see the current data versus the proposed new data. SELECT c.contactid, c.emailaddress1 AS 'CurrentEmail', upd.prevEmail AS 'NewEmail' FROM contact c INNER JOIN #EmailUpdates upd ON c.contactid = upd.contactId; -- Step 4: If you are satisfied with the preview, run the UPDATE statement below. /* -- Uncomment the following lines to execute the update UPDATE c SET emailaddress1 = upd.prevEmail FROM contact c INNER JOIN #EmailUpdates upd ON c.contactid = upd.contactId; -- Check the number of rows affected to confirm the update was successful. -- We must convert the number @@ROWCOUNT to a string to print it. PRINT CONVERT(VARCHAR, @@ROWCOUNT) + ' rows updated.'; -- Step 5: Clean up the temporary table. DROP TABLE #EmailUpdates; */
To run this query, you'll need to uncheck the Prevent UPDATE without WHERE option in the Settings.
If you're not used to working with SQL (or SQL 4 CDS), know that you can select the portion of the code you want to run. So after executing the first steps of the code, when you uncomment the last part, you can just select the remaining part before hitting Execute (or F5), just like this:

Don't stop learning!