Account verification link in web-based mail readers

I’m running Indico 3.2.9. I have account moderation turned on in indico.conf:

LOCAL_MODERATION = True

For a user to create a new login, they must create a account via the “Create a new Indico profile” page. After filling out the page, they receive an email with a verification link. If they click on that link within a mail reader such as Thunderbird, there’s no problem.

However, if they’re using a browser-based mail reader such as mail.google.com or Roundcube, clicking on that link takes them back to the “Create a new Indico profile” page. For them it becomes an endless loop of requesting a new profile and receiving yet another verification email.

When they contact me (the Indico site admin), I can give them a simple solution: Just copy-and-paste the verification link into the URL field of their web browser. But that’s a work-around, not a solution.

Is there something I can do to trace the source of the problem?

As a follow-up:

I noticed that my Indico version (3.2.9) was an old version. I tried to do the upgrade as documented in:

However, when I got to the following command in that second weblink:

indico setup upgrade-python --force-version 3.12

I got a Python error. I tried to track that down, eventually tried a fresh install of Indico, got into Python/database mis-match hell. I had to restore my indico virtual machine and postgresql database from backups.

To avoid topic drift, I’ll stick with my original question: Within the context of Indico 3.2.9, is there a solution to the problem?

That looks like either your email client or your email server is somehow breaking links.

Email validation tokens do not rely on any session state.

When accessing https://<yourindicoserver>/register/?token=....... it creates a session (identified via a cookie like any other web session) and redirects you to /register/ so the token does not stay in the URL.

The only explanation I can imagine for the problem you described occurring is that somehow the redirect got resolved by the email client (or some very broken email security software) and the browser was then only redirected to the final location. But again, this would be extremely broken behavior violating pretty much all web standards..

Can you reproduce it? If yes, please use your browser’s dev tools to check which URLs are opened by your browser when accessing the validation link from the email.

PS: About the Python error, please open a separate thread unless one of these existing topics matches your problem.

Given your response, I think I should clarify:

At least at first, this wasn’t happening to me. I read my mail through an email client. I only learned of the problem when users reported it to me.

When I asked them, they reported they used different browsers (Chrome and Firefox). For mail readers, they used browser-based Gmail.

As far as I know, no one who read their mail through a mail client client like Thunderbird or Apple Mail had a problem. Our Indico site has been up for about two years (hence the old version) and this was the first time anyone reported a problem of this sort.

In my own tests, I tried Chrome and Firefox, and tested clicking on registration links in both Gmail and Roundcube. The behavior was consistent: Clicking on the links via a web browser resulted in the problematic “registration loop”. Copying-and-pasting the same link into a browser’s URL, or clicking the email link via mail client, worked just fine.

So: The effect is quite reproducible, given that other people see it; it’s not just me.

I’m not facile with web development tools in either Firefox or Chrome. What I could do is examine the page source (in Roundcube in my particular case) in my web browser, and view the email source in my mail client (Thunderbird). The https://<yourindicoserver>/register/?token=... links were the same. To make sure, I copied the links into files and compared the links using diff; the files were identical.

Given that the obvious next step (upgrading to the current Indico version) is problematic for me, my current “solution” is to live with it. When each user reports the problem to me, I tell them to copy-and-paste the link into their browser URL.

Updating Indico is very much advised, but won’t make a difference for this particular thing.

What I could do is examine the page source (in Roundcube in my particular case) in my web browser, and view the email source in my mail client (Thunderbird). The https://<yourindicoserver>/register/?token=... links were the same. To make sure, I copied the links into files and compared the links using diff; the files were identical.

The problem is that web mailers may be doing weird stuff with link on click - so while inspecting the link you have the proper URL, but when clicking it you get something else (google’s own tracking, link security checks, whatever)…

Fool that I am, I just realized the obvious: Check the web logs.

I looked at indico.log. I found these lines, which represent my most recent attempt to test this problem:

2025-04-22 04:47:27,946  INFO     0c09c2f02cae4f62  -       indico.rh                 GET /login/ [IP=10.44.47.2] [PID=76645]
2025-04-22 04:47:31,574  INFO     8afedd12ef1349a2  -       indico.rh                 GET /register/ [IP=10.44.47.2] [PID=76749]
2025-04-22 04:47:31,861  INFO     25e0e45ea2584924  -       indico.rh                 GET /api/captcha/generate [IP=10.44.47.2] [PID=76751]
2025-04-22 04:47:46,202  INFO     c535c665f79b4a22  -       indico.rh                 POST /register/ [IP=10.44.47.2] [PID=76751]
2025-04-22 04:47:46,259  INFO     f4aa8b6667da41db  -       indico.rh                 GET /register/ [IP=10.44.47.2] [PID=76749]
2025-04-22 04:47:47,238  INFO     0000000000000000  -       indico.emails             Sent email "[Indico] Verify your email"
2025-04-22 04:54:14,159  INFO     8d7067b5bb3c4551  -       indico.rh                 GET /register/?token=<token> [IP=10.44.47.2] [PID=76751]
2025-04-22 04:54:14,185  INFO     eb8a4fc2eecb41cc  -       indico.rh                 GET /register/ [IP=10.44.47.2] [PID=76751]
2025-04-22 04:54:14,533  INFO     5c3e691ab805434b  -       indico.rh                 GET /api/captcha/generate [IP=10.44.47.2] [PID=76749]
2025-04-22 04:59:53,859  INFO     07dc6d884c3f4843  -       indico.rh                 GET /register/?token=<token> [IP=10.44.47.2] [PID=76751]
2025-04-22 04:59:53,883  INFO     f4282ba279a04144  -       indico.rh                 GET /register/ [IP=10.44.47.2] [PID=76751]

Here’s how I think it breaks down:

  • At 04:47 I visit the Indico login page, and click on create one here. I fill in the captcha, and Indico sends the verification email.
  • At 04:54, I click on the verification link in the browser. That takes me to the captcha page again.
  • At 04:59, I click on the link within my email client. There’s nothing more recorded in indico.log, but I’m taken to the page that asks me to enter account information.

The key point here is that <token> is identical at 04:54 and 04:59. I again confirmed this with diff.

Next I looked at apache/access.log. The two access attempts don’t quite leave the same messages (a blend of HTTPD 200 and 304 codes), but I was able to confirm that <token> was the same in the apache log as it was in the indico log.

The initial key difference between how the Indico web server responds is:

For the access via the browser:

10.44.47.2 - - [22/Apr/2025:04:54:14 -0400] "GET /assets/i18n/en_US.js HTTP/1.1" 304 - "https://<servername>/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0"

Assuming I understand the HTTP status codes correctly, for the browser access of en_US.js the apache server returns 304, “resource has not been modified since the version specified by the request headers”.

For the email client access:

10.44.47.2 - - [22/Apr/2025:04:59:53 -0400] "GET /assets/i18n/en_US.js HTTP/1.1" 200 73 "https://<servername>/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0"
10.44.47.2 - - [22/Apr/2025:04:59:53 -0400] "GET /assets/i18n/en_US-react.js HTTP/1.1" 304 - "https://<servername>/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0"

For the mail client access, for en_US.js apache returns 200 “Standard response for successful HTTP requests”. After a request for en_US.js, there’s a subsequent request for en_US-react.js which is not performed for the browser access.

All of which tells me nothing, except that I don’t see a difference in the tokens themselves or why Indico would respond differently to the HTTPD requests. If I believe the names, en_US.js suggests a localization of some sort. It doesn’t looking like a smoking gun to me.

Does any of this suggest anything to you?

One of the things to keep in mind here is, that the confirmation mail is based on the plain text mail template, so any link being ‘clickable’ is a browser or webmail client feature ( e.g. in the gmail app this link is no directly clickable). So probably the heuristics in what should be part of a clickable link is broken here ( i suspect it could be the . which is part of the token).
In the longer run we should probably switch to all mails being either pure html or at least a multipart mail with both plain and html content.

Oh, . at the end indeed sounds like a likely culprit if that was the case here!

I don’t like the idea of sending pure HTML mails, but a short-term fix may be to wrap the url in <.......> which typically tells email clients to not wrap or otherwise mess up any parts of the link inside there

I haven’t included the text for <token> in the outputs, to both spare on reading and just in case revealing the token somehow reveals my private key or something like that. However, I can confirm that in the original verification email, and in the Indico access logs, the token in this case does not end in a .. It ends with an A.

If I understand your statement, wouldn’t all of the tokens created by my Indico server have to end in .? That seems unlikely.

If it’s relevant: The token in question does have periods within the token itself. For both the browser-based link and the email-client-based link, the log entry is basically the same:

10.44.47.2 - - [22/Apr/2025:04:59:53 -0400] "GET /register/?token=<token> HTTP/1.1" 302 207 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0"

Again, the string I’ve identified as <token> is identical in the two log entries, and matches the token I see in the page sources of the email and the browser text. The only thing that differs is the time of the GET.

The email validation token is valid for 1h. So after that (or after it has been used to finish the registration with that email address) sharing it is harmless. You could also overwrite random letters/numbers in it with xxxxx to break it.

Ah! In that case, the log entry in apache/access.log from clicking the browser link is:

10.44.47.2 - - [22/Apr/2025:04:54:14 -0400] "GET /register/?token=InNlbGlnbWFuQGFyZ290aGFsZC5jb20i.aAdXsg.BAX0mdjBNu41FM0xJf9c06k5diA HTTP/1.1" 302 207 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0"

The corresponding log entry from the clicking the link in the email client is:

10.44.47.2 - - [22/Apr/2025:04:59:53 -0400] "GET /register/?token=InNlbGlnbWFuQGFyZ290aGFsZC5jb20i.aAdXsg.BAX0mdjBNu41FM0xJf9c06k5diA HTTP/1.1" 302 207 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0"