398e258ed1330421291f943298e7f801f7b05bf8
hiram
  Thu Apr 23 15:05:02 2026 -0700
and send notification email to the requesting user refs #31811

diff --git src/hg/utils/otto/userRequests/ottoRequest.py src/hg/utils/otto/userRequests/ottoRequest.py
index e148a9ced65..dca2df5f3ef 100755
--- src/hg/utils/otto/userRequests/ottoRequest.py
+++ src/hg/utils/otto/userRequests/ottoRequest.py
@@ -68,35 +68,45 @@
             'requestTime': fields[6],
         })
     return rows
 
 
 def hgsqlUpdate(db, sql):
     """Run a SQL update/insert statement via hgsql."""
     cmd = ['hgsql', db, '-N', '-B', '-e', sql]
     result = subprocess.run(cmd, capture_output=True, text=True)
     if result.returncode != 0:
         print(f"hgsql update error: {result.stderr.strip()}", file=sys.stderr)
         return False
     return True
 
 
-def sendMail(toAddr, subject, body):
-    """Send email via /usr/sbin/sendmail."""
-    message = f"To: {toAddr}\nSubject: {subject}\n\n{body}\n"
-    result = subprocess.run(['/usr/sbin/sendmail', '-t'],
-                            input=message, capture_output=True, text=True)
+def sendMail(toAddr, subject, body, fromAddr=None):
+    """Send email via /usr/sbin/sendmail.
+    If fromAddr is provided it is used as the envelope sender (-f)
+    and the From: header so that bounces return to that address."""
+    headers = f"To: {toAddr}\nSubject: {subject}"
+    if fromAddr:
+        headers = (f"From: {fromAddr}\n"
+                   f"Reply-To: {fromAddr}\n"
+                   f"Return-Path: {fromAddr}\n"
+                   f"{headers}")
+    message = f"{headers}\n\n{body}\n"
+    cmd = ['/usr/sbin/sendmail', '-t']
+    if fromAddr:
+        cmd += ['-f', fromAddr]
+    result = subprocess.run(cmd, input=message, capture_output=True, text=True)
     if result.returncode != 0:
         print(f"Warning: sendmail failed: {result.stderr.strip()}",
               file=sys.stderr)
         return False
     return True
 
 
 def main():
     parser = argparse.ArgumentParser(
         description='Process pending ottoRequest entries.')
     parser.add_argument('-c', '--conf',
                         default='/usr/local/apache/cgi-bin/hg.conf',
                         help='Path to hg.conf [default: %(default)s]')
     args = parser.parse_args()
 
@@ -123,27 +133,52 @@
     for req in pending:
         subject = f"ottoRequest #{req['id']}: {req['requestType']} pending"
         body = (
             f"##################################################\n"
             f"Pending {req['requestType']} request #{req['id']}\n"
             f"\n"
             f"  From:    {req['fromDb']}\n"
             f"  To:      {req['toDb']}\n"
             f"  Email:   {req['email']}\n"
             f"  Comment: {req['comment']}\n"
             f"  Time:    {req['requestTime']}\n"
             f"##################################################\n"
             f"testing ottoRequest watch cron job\n"
             f"##################################################\n"
         )
-        if sendMail(notifyEmail, subject, body):
+        if sendMail(notifyEmail, subject, body, fromAddr=notifyEmail):
 #           print(f"Notified {notifyEmail} about request #{req['id']}")
             hgsqlUpdate(dbName,
                 f"UPDATE {table} SET doneStatus = 1"
                 f" WHERE id = {req['id']}")
         else:
             print(f"Failed to notify about request #{req['id']}",
                   file=sys.stderr)
 
+        # send acknowledgment to the requesting user
+        userEmail = req.get('email', '')
+        if userEmail:
+            userSubject = (f"UCSC Genome Browser: your {req['requestType']}"
+                           f" request has been received")
+            userBody = (
+                f"Your request for chain/liftOver files has been received\n"
+                f"and is being processed.\n"
+                f"\n"
+                f"Request details:\n"
+                f"  Type:      {req['requestType']}\n"
+                f"  From:      {req['fromDb']}\n"
+                f"  To:        {req['toDb']}\n"
+                f"  Submitted: {req['requestTime']}\n"
+                f"\n"
+                f"You will receive another email when your files are ready.\n"
+                f"\n"
+                f"- UCSC Genome Browser\n"
+            )
+            if not sendMail(userEmail, userSubject, userBody,
+                           fromAddr=notifyEmail):
+                print(f"Warning: failed to send acknowledgment to"
+                      f" {userEmail} for request #{req['id']}",
+                      file=sys.stderr)
+
 
 if __name__ == '__main__':
     main()