Page MenuHomePhabricator

Echo: Generate periodic web notification to nudge users to confirm an unverified email address
Closed, ResolvedPublic

Description

Summary

It is not obvious to users when they have an unverified email address. Without a verified email address, we can only send password reset notifications. We also cannot know if the user controls the email associated with the account. In this task, we'll use Echo notifications to periodically remind active users with unverified email addresses that they should confirm their email. The notification would be web and push notification for apps, as well as email.

Background

  • There are approximately 200,000 users who have some amount of activity in the last 90 days, with an unverified email address
  • Handling Notification Frequency: We should send the notification to every user who does not have a verified email, every ~30 days. It does not matter if the user has received the notification before. The user should not receive more than one notification on a given local wiki in 30 days.
  • Multi-wiki Considerations: We should generate the notification on every wiki that shows activity for the user, using cuci_user to see where the user has been active. e.g. if a user is active on enwiki and frwiki, it is OK to generate notifications for both of those wikis.
  • Opt out: The opt-out from this notification would either be verifying the email address, or unsetting the email address on the account. The user can also disable the notification in Special:Preferences (default Echo behavior)

Spec

  • Category: alert
  • Icon: linkSecure
  • Text: Please verify your email address now
  • Secondary text: Confirm your email for security purposes
  • Primary action: Confirm email (link to Special:ConfirmEmail)
  • Secondary action: View email preferences (link to Special:Preferences#mw-prefsection-personal-email)

User story

  • As an active user (active = logged-in or edited recently) I want to know if my email address is unverified.

Technical notes

  • We can use the cuci_user table in centralauth to detect global user activity (logins, edits, etc) over a 90 day period.
  • We can query this data via a maintenance script every 30 days and generate an Echo notification for users who have been active in the last 30 days.

Acceptance criteria

  • Maintenance script exists that generates an Echo notification for users active in last 30 days who have unverified email addresses
  • Links and actions match what is in the Spec section above
  • Maintenance script is run every month on WMF wikis automatically

Related tasks

Details

Reference
bz56074
Related Changes in Gerrit:
Show related patches Customize query in gerrit

Related Objects

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

Change #1159418 had a related patch set uploaded (by Máté Szabó; author: Máté Szabó):

[mediawiki/extensions/Echo@master] Add missing labels for email confirmation reminder preferences

https://gerrit.wikimedia.org/r/1159418

Change #1159418 merged by jenkins-bot:

[mediawiki/extensions/Echo@master] Add missing labels for email confirmation reminder preferences

https://gerrit.wikimedia.org/r/1159418

Change #1159438 had a related patch set uploaded (by Máté Szabó; author: Máté Szabó):

[mediawiki/extensions/Echo@wmf/1.45.0-wmf.5] Add missing labels for email confirmation reminder preferences

https://gerrit.wikimedia.org/r/1159438

Change #1159438 merged by jenkins-bot:

[mediawiki/extensions/Echo@wmf/1.45.0-wmf.5] Add missing labels for email confirmation reminder preferences

https://gerrit.wikimedia.org/r/1159438

Mentioned in SAL (#wikimedia-operations) [2025-06-16T14:10:36Z] <mszabo@deploy1003> Started scap sync-world: Backport for [[gerrit:1159438|Add missing labels for email confirmation reminder preferences (T58074)]]

Mentioned in SAL (#wikimedia-operations) [2025-06-16T14:48:29Z] <mszabo@deploy1003> mszabo: Backport for [[gerrit:1159438|Add missing labels for email confirmation reminder preferences (T58074)]] synced to the testservers (see https://wikitech.wikimedia.org/wiki/Mwdebug). Changes can now be verified there.

Mentioned in SAL (#wikimedia-operations) [2025-06-16T15:04:05Z] <mszabo@deploy1003> Finished scap sync-world: Backport for [[gerrit:1159438|Add missing labels for email confirmation reminder preferences (T58074)]] (duration: 53m 29s)

Also noting that recently someone reported issues wrt wgEmailAuthentication, where a spamfilter was accessing the InvalidateEmail link in that email, causing it to be invalidated before he could use the emailauth link. That is something we will have to consider if we use a similar type link in this situation.

If a spamfilter just sends GET requests to arbitrary links in an email, I don't think it's reasonable to expect us to accommodate that. Email links that take action on GET are very common - some jurisdictions require one-click unsubscribe links in commercial email, for example.

If it does somehow mark those requests as abnormal (e.g. a Sec-Purpose: prefetch header), we could ignore those, but otherwise, I wouldn't change email format because of a poorly configured tool which will run into trouble with many other websites as well.

If it's deployed (I can't say since I don't have an unconfirmed account), have we seen a bump in number of confirmed emails?

@UOzurumba moved this task from Not ready to announce to Announce in next Tech/News on the User-notice board.

(is this ready to announce yet, given T58074#10978245?)

OKryva-WMF added a subscriber: mszabo.

Change #1192178 had a related patch set uploaded (by Dreamy Jazz; author: Dreamy Jazz):

[mediawiki/extensions/WikimediaMaintenance@master] Add sendVerifyEmailReminderNotification maintenance script

https://gerrit.wikimedia.org/r/1192178

These patches are in the process of merging. After they've merged, we should wait until they're in group0 next week, and do a manual invocation of the script on testwiki. After the code is in group2, we could do a manual run across all wikis. Assuming that goes fine, we could then implement the operations/puppet patch so that this runs monthly.

Should the Tech/News notice about this be sent out before the manual run of the script across all wikis? IMO this would make sense, as then communities would hopefully know in advance that these notifications are going to be sent, rather than them potentially coming as a surprise. (And if that should happen, should this be announced in the next Tech/News?)

Change #1192178 merged by jenkins-bot:

[mediawiki/extensions/WikimediaMaintenance@master] Add sendVerifyEmailReminderNotification maintenance script

https://gerrit.wikimedia.org/r/1192178

Should the Tech/News notice about this be sent out before the manual run of the script across all wikis? IMO this would make sense, as then communities would hopefully know in advance that these notifications are going to be sent, rather than them potentially coming as a surprise. (And if that should happen, should this be announced in the next Tech/News?)

Sure. Moved this task on the User-notice project to reflect that.

@Dreamy_Jazz how should this be worded for Tech News please?

I am clear periodic web notification to nudge users to confirm an unverified email address will now be generated. However is it just testwiki? And roughly which week will this change be obvious?

Change #1143801 merged by jenkins-bot:

[mediawiki/extensions/WikimediaMaintenance@master] Expand sendVerifyEmailReminderNotification maintenance script

https://gerrit.wikimedia.org/r/1143801

I am clear periodic web notification to nudge users to confirm an unverified email address will now be generated.

Yes, this is correct. Specifically we will only sent a notification to users who:

  • Have an email on their account
  • The email is not verified
  • The user is not locked (i.e. must not be prevented from logging in)
  • The user has performed at least one action on any wiki in the last 30 days

However is it just testwiki?

This will be all wikis that use central accounts / SUL (i.e. not private wikis or fishbowl wikis)

And roughly which week will this change be obvious?

Probably next week

Suggested wording for Tech News:

Users who have not verified their email address will soon be receiving monthly reminders to do so. This is because users who have verified their email can more easily recover their account. These reminders will not be shown if the user is inactive or removes the unverified email from their account.

I'd like to pass it by others before it's used though to double check the wording is good

After they've merged, we should wait until they're in group0 next week, and do a manual invocation of the script on testwiki. After the code is in group2, we could do a manual run across all wikis. Assuming that goes fine, we could then implement the operations/puppet patch so that this runs monthly.

As discussed off Phab, the script does not support filtering based on a wiki as the list of users to email is fetched from a global list. Therefore, we can run the script whenever this script reaches any wikis and the run of the script would notify all users.

We should run the script once:

  • The Tech/News entry has been out for long enough for people to notice
  • We have verified that the script works by running it on some kind of test instance, to replace the need to run it per-wiki for a first testwiki only run (we cannot use the beta cluster for this test due to the need to have CheckUser installed)

Once the script has been run once, we should look at how long it took to run. If it takes a long while to run, we may need to consider modifying the script to process a smaller batch of active users (i.e. we make the script process users per-wiki such that each instance only targets the users with their home wiki as that wiki so that each invocation of the script runs for overall less time)

Finally, we should set the operations/puppet definition once we are happy with this. The first run should be a month after the script first ran and then run monthly after that

Mentioned in SAL (#wikimedia-operations) [2025-10-17T15:33:14Z] <Dreamy_Jazz> Ran mwscript-k8s --comment='First emails to users to get them to confirm their email address for T58074' extensions/WikimediaMaintenance/sendVerifyEmailReminderNotification.php --wiki=metawiki 20250917000000

The remaining work for this ticket is to set the operations/puppet definition. The first run looked to be a success, so we should be able to define this when we have time

Putting this here, just for future reference:

mysql:[email protected] [centralauth]> select if( gu_email_authenticated is null, 'no', 'yes') authed, count(*) from globaluser where gu_email != '' group by authed;
+--------+----------+
| authed | count(*) |
+--------+----------+
| no     | 38918571 |
| yes    | 22848701 |
+--------+----------+
2 rows in set (1 min 31.513 sec)

Re-ran the query that Ladsgroup ran for interest today:

select if( gu_email_authenticated is null, 'no', 'yes') authed, count(*) from globaluser where gu_email != '' group by authed;
+--------+----------+
| authed | count(*) |
+--------+----------+
| no     | 38918673 |
| yes    | 22868508 |
+--------+----------+

Seems like so far:

  • Only ~100 additional users have not verified their email
  • ~20,000 additional users have verified their email

That doesn't necessarily mean this work caused the increase in verified emails, as this does not limit the query to only users who got the email (i.e. we only target active users). However, I can say I did see users actively verify their email after getting the email we sent based on logstash logs and DB queries for individual users (as part of verifying that emails worked)

To make it possible to run this on a schedule, we need to make the timestamp argument support a relative timestamp.

That gave me an idea. Let's compare number of emails being authenticated in the past days when the day of authentication and user registration is different:

mysql:[email protected] [centralauth]> select left(gu_email_authenticated, 8), count(*) from globaluser where gu_email_authenticated is not null and left(gu_email_authenticated, 8) != left(gu_regi
stration, 8) and gu_email_authenticated like '202510%' group by left(gu_email_authenticated, 8);
+---------------------------------+----------+
| left(gu_email_authenticated, 8) | count(*) |
+---------------------------------+----------+
| 20251001                        |     1249 |
| 20251002                        |     1254 |
| 20251003                        |     1156 |
| 20251004                        |     1018 |
| 20251005                        |     1151 |
| 20251006                        |     1257 |
| 20251007                        |     1242 |
| 20251008                        |     1287 |
| 20251009                        |     1288 |
| 20251010                        |     1192 |
| 20251011                        |     1077 |
| 20251012                        |     1080 |
| 20251013                        |     1217 |
| 20251014                        |     1161 |
| 20251015                        |     1283 |
| 20251016                        |     1256 |
| 20251017                        |    10972 |
| 20251018                        |     3872 |
| 20251019                        |     1915 |
| 20251020                        |     2144 |
| 20251021                        |      841 |
+---------------------------------+----------+
21 rows in set (1 min 20.434 sec)

This shows around 14K users have verified their emails due to the echo notification.

Change #1197654 had a related patch set uploaded (by Dreamy Jazz; author: Dreamy Jazz):

[mediawiki/extensions/WikimediaMaintenance@master] Update sendVerifyEmailReminderNotification to use relative timestamp

https://gerrit.wikimedia.org/r/1197654

Change #1197658 had a related patch set uploaded (by Dreamy Jazz; author: Dreamy Jazz):

[operations/puppet@production] mediawiki: Run sendVerifyEmailReminderNotification.php monthly

https://gerrit.wikimedia.org/r/1197658

That gave me an idea. Let's compare number of emails being authenticated in the past days when the day of authentication and user registration is different:

mysql:[email protected] [centralauth]> select left(gu_email_authenticated, 8), count(*) from globaluser where gu_email_authenticated is not null and left(gu_email_authenticated, 8) != left(gu_regi
stration, 8) and gu_email_authenticated like '202510%' group by left(gu_email_authenticated, 8);
+---------------------------------+----------+
| left(gu_email_authenticated, 8) | count(*) |
+---------------------------------+----------+
| 20251001                        |     1249 |
| 20251002                        |     1254 |
| 20251003                        |     1156 |
| 20251004                        |     1018 |
| 20251005                        |     1151 |
| 20251006                        |     1257 |
| 20251007                        |     1242 |
| 20251008                        |     1287 |
| 20251009                        |     1288 |
| 20251010                        |     1192 |
| 20251011                        |     1077 |
| 20251012                        |     1080 |
| 20251013                        |     1217 |
| 20251014                        |     1161 |
| 20251015                        |     1283 |
| 20251016                        |     1256 |
| 20251017                        |    10972 |
| 20251018                        |     3872 |
| 20251019                        |     1915 |
| 20251020                        |     2144 |
| 20251021                        |      841 |
+---------------------------------+----------+
21 rows in set (1 min 20.434 sec)

This shows around 14K users have verified their emails due to the echo notification.

Nice, thanks for looking at this data. Good to see that it definitely had a visible positive impact in the number of email verifications per-day

Change #1197654 merged by jenkins-bot:

[mediawiki/extensions/WikimediaMaintenance@master] Update sendVerifyEmailReminderNotification to use relative timestamp

https://gerrit.wikimedia.org/r/1197654

Change #1197663 had a related patch set uploaded (by Dreamy Jazz; author: Dreamy Jazz):

[mediawiki/extensions/WikimediaMaintenance@wmf/1.45.0-wmf.24] Update sendVerifyEmailReminderNotification to use relative timestamp

https://gerrit.wikimedia.org/r/1197663

Change #1197665 had a related patch set uploaded (by Dreamy Jazz; author: Dreamy Jazz):

[mediawiki/extensions/WikimediaMaintenance@wmf/1.45.0-wmf.23] Update sendVerifyEmailReminderNotification to use relative timestamp

https://gerrit.wikimedia.org/r/1197665

Change #1197663 merged by jenkins-bot:

[mediawiki/extensions/WikimediaMaintenance@wmf/1.45.0-wmf.24] Update sendVerifyEmailReminderNotification to use relative timestamp

https://gerrit.wikimedia.org/r/1197663

Change #1197665 merged by jenkins-bot:

[mediawiki/extensions/WikimediaMaintenance@wmf/1.45.0-wmf.23] Update sendVerifyEmailReminderNotification to use relative timestamp

https://gerrit.wikimedia.org/r/1197665

Mentioned in SAL (#wikimedia-operations) [2025-10-21T14:43:21Z] <dreamyjazz@deploy2002> Started scap sync-world: Backport for [[gerrit:1197665|Update sendVerifyEmailReminderNotification to use relative timestamp (T58074)]], [[gerrit:1197663|Update sendVerifyEmailReminderNotification to use relative timestamp (T58074)]]

Mentioned in SAL (#wikimedia-operations) [2025-10-21T14:47:29Z] <dreamyjazz@deploy2002> dreamyjazz: Backport for [[gerrit:1197665|Update sendVerifyEmailReminderNotification to use relative timestamp (T58074)]], [[gerrit:1197663|Update sendVerifyEmailReminderNotification to use relative timestamp (T58074)]] synced to the testservers (see https://wikitech.wikimedia.org/wiki/Mwdebug). Changes can now be verified there.

Mentioned in SAL (#wikimedia-operations) [2025-10-21T14:52:13Z] <dreamyjazz@deploy2002> Finished scap sync-world: Backport for [[gerrit:1197665|Update sendVerifyEmailReminderNotification to use relative timestamp (T58074)]], [[gerrit:1197663|Update sendVerifyEmailReminderNotification to use relative timestamp (T58074)]] (duration: 08m 52s)

Change #1197658 merged by JHathaway:

[operations/puppet@production] mediawiki: Run sendVerifyEmailReminderNotification.php monthly

https://gerrit.wikimedia.org/r/1197658

Dreamy_Jazz updated the task description. (Show Details)

Puppet change is deployed and so this can be marked as done. We can verify the script is running as expected once the 17th of November rolls around

I reran the query one more time, and it looks like the script is probably working. You can see clear spikes on Nov 17 and on Jan 17 (but not Dec 17 for some reason).

1[email protected](centralauth)> select left(gu_email_authenticated, 8), count(*) from globaluser where gu_email_authenticated is not null and left(gu_email_authenticated, 8) != left(gu_registration, 8) and gu_email_authenticated >= '20251001000000' group by left(gu_email_authenticated, 8);
2+---------------------------------+----------+
3| left(gu_email_authenticated, 8) | count(*) |
4+---------------------------------+----------+
5| 20251001 | 1244 |
6| 20251002 | 1246 |
7| 20251003 | 1151 |
8| 20251004 | 1015 |
9| 20251005 | 1148 |
10| 20251006 | 1252 |
11| 20251007 | 1234 |
12| 20251008 | 1286 |
13| 20251009 | 1285 |
14| 20251010 | 1186 |
15| 20251011 | 1067 |
16| 20251012 | 1077 |
17| 20251013 | 1214 |
18| 20251014 | 1153 |
19| 20251015 | 1282 |
20| 20251016 | 1251 |
21| 20251017 | 10943 | <----- script ran
22| 20251018 | 3856 |
23| 20251019 | 1909 |
24| 20251020 | 2136 |
25| 20251021 | 1566 |
26| 20251022 | 1427 |
27| 20251023 | 1349 |
28| 20251024 | 1184 |
29| 20251025 | 1079 |
30| 20251026 | 1051 |
31| 20251027 | 1202 |
32| 20251028 | 1221 |
33| 20251029 | 1141 |
34| 20251030 | 1087 |
35| 20251031 | 1002 |
36| 20251101 | 945 |
37| 20251102 | 1062 |
38| 20251103 | 1154 |
39| 20251104 | 1212 |
40| 20251105 | 1140 |
41| 20251106 | 957 |
42| 20251107 | 575 |
43| 20251108 | 518 |
44| 20251109 | 582 |
45| 20251110 | 672 |
46| 20251111 | 678 |
47| 20251112 | 604 |
48| 20251113 | 648 |
49| 20251114 | 629 |
50| 20251115 | 561 |
51| 20251116 | 638 |
52| 20251117 | 9030 | <----- script ran
53| 20251118 | 4113 |
54| 20251119 | 1461 |
55| 20251120 | 1039 |
56| 20251121 | 834 |
57| 20251122 | 756 |
58| 20251123 | 769 |
59| 20251124 | 804 |
60| 20251125 | 709 |
61| 20251126 | 642 |
62| 20251127 | 602 |
63| 20251128 | 499 |
64| 20251129 | 569 |
65| 20251130 | 645 |
66| 20251201 | 725 |
67| 20251202 | 787 |
68| 20251203 | 1298 |
69| 20251204 | 1403 |
70| 20251205 | 1558 |
71| 20251206 | 1324 |
72| 20251207 | 1369 |
73| 20251208 | 1466 |
74| 20251209 | 1394 |
75| 20251210 | 1266 |
76| 20251211 | 1222 |
77| 20251212 | 1380 |
78| 20251213 | 1632 |
79| 20251214 | 1511 |
80| 20251215 | 1630 |
81| 20251216 | 1380 |
82| 20251217 | 1438 | <----- script ran
83| 20251218 | 1223 |
84| 20251219 | 1094 |
85| 20251220 | 995 |
86| 20251221 | 1110 |
87| 20251222 | 1175 |
88| 20251223 | 1099 |
89| 20251224 | 973 |
90| 20251225 | 857 |
91| 20251226 | 1104 |
92| 20251227 | 1114 |
93| 20251228 | 1115 |
94| 20251229 | 1207 |
95| 20251230 | 1134 |
96| 20251231 | 1024 |
97| 20260101 | 935 |
98| 20260102 | 1044 |
99| 20260103 | 1134 |
100| 20260104 | 1095 |
101| 20260105 | 1095 |
102| 20260106 | 1010 |
103| 20260107 | 1134 |
104| 20260108 | 1169 |
105| 20260109 | 1046 |
106| 20260110 | 1045 |
107| 20260111 | 1107 |
108| 20260112 | 1117 |
109| 20260113 | 1193 |
110| 20260114 | 1146 |
111| 20260115 | 1248 |
112| 20260116 | 1122 |
113| 20260117 | 7828 | <----- script ran
114| 20260118 | 3979 |
115| 20260119 | 2279 |
116| 20260120 | 1844 |
117| 20260121 | 1391 |
118| 20260122 | 1337 |
119| 20260123 | 1203 |
120| 20260124 | 1108 |
121| 20260125 | 1024 |
122| 20260126 | 1126 |
123| 20260127 | 1048 |
124+---------------------------------+----------+
125119 rows in set (21.202 sec)

I reran the query one more time, and it looks like the script is probably working. You can see clear spikes on Nov 17 and on Jan 17 (but not Dec 17 for some reason).

The December run had a failure with the script which we fixed in time for the January run. We had attempted to rerun the December run, but it failed again so we decided to leave it as-is to avoid spamming some of the users who had received the notifications