Bug: [REFACTOR] Move Hardcoded Email Subjects to Constants Across the User Related Files



### Feature Description

In the current implementation, email subjects are hardcoded at multiple places across the codebase when constructing email content. To improve maintainability and avoid magic strings, each unique subject should be moved to its own constant. The goal of this issue is to identify all the places where email subjects are hardcoded, create a corresponding constant for each one, and replace the hardcoded values with the newly defined constants.

### Possible Implementation

- Search the codebase for all instances where email subjects are hardcoded.
  Example: https://github.com/juspay/hyperswitch/blob/b2364414edab6d44e276f2133bc988610693f155/crates/router/src/core/user.rs#L707
- For each unique subject, create a new constant in `crates/router/src/consts/user.rs`.
- Refactor the code by replacing the hardcoded subjects with their respective constants.


### Have you spent some time checking if this feature request has been raised before?

- [X] I checked and didn't find a similar issue

### Submission Process:
- Ask the maintainers for assignment of the issue, you can request for assignment by commenting on the issue itself.
- Once assigned, submit a pull request (PR).
- Maintainers will review and provide feedback, if any. 
- Maintainers can unassign issues due to inactivity, [read more here](https://github.com/juspay/hyperswitch/wiki/Hacktoberfest-Contribution-Rules).

Refer [here](https://github.com/juspay/hyperswitch/blob/main/docs/TERMS_OF_CONTEST.md) for Terms and conditions for the contest.
diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs
index 9e70cb2b96b..728933a4614 100644
--- a/crates/router/src/consts.rs
+++ b/crates/router/src/consts.rs
@@ -86,6 +86,11 @@ pub const EMAIL_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24; // 1 day
 #[cfg(feature = "email")]
 pub const EMAIL_TOKEN_BLACKLIST_PREFIX: &str = "BET_";
 
+pub const EMAIL_SUBJECT_API_KEY_EXPIRY: &str = "API Key Expiry Notice";
+pub const EMAIL_SUBJECT_DASHBOARD_FEATURE_REQUEST: &str = "Dashboard Pro Feature Request by";
+pub const EMAIL_SUBJECT_APPROVAL_RECON_REQUEST: &str =
+    "Approval of Recon Request - Access Granted to Recon Dashboard";
+
 pub const ROLE_INFO_CACHE_PREFIX: &str = "CR_INFO_";
 
 #[cfg(feature = "olap")]
diff --git a/crates/router/src/consts/user.rs b/crates/router/src/consts/user.rs
index 6ac2b08e6bb..5984a876503 100644
--- a/crates/router/src/consts/user.rs
+++ b/crates/router/src/consts/user.rs
@@ -26,3 +26,10 @@ pub const REDIS_TOTP_SECRET_TTL_IN_SECS: i64 = 15 * 60; // 15 minutes
 
 pub const REDIS_SSO_PREFIX: &str = "SSO_";
 pub const REDIS_SSO_TTL: i64 = 5 * 60; // 5 minutes
+
+/// Email subject
+pub const EMAIL_SUBJECT_SIGNUP: &str = "Welcome to the Hyperswitch community!";
+pub const EMAIL_SUBJECT_INVITATION: &str = "You have been invited to join Hyperswitch Community!";
+pub const EMAIL_SUBJECT_MAGIC_LINK: &str = "Unlock Hyperswitch: Use Your Magic Link to Sign In";
+pub const EMAIL_SUBJECT_RESET_PASSWORD: &str = "Get back to Hyperswitch - Reset Your Password Now";
+pub const EMAIL_SUBJECT_NEW_PROD_INTENT: &str = "New Prod Intent";
diff --git a/crates/router/src/core/recon.rs b/crates/router/src/core/recon.rs
index d5f824e0cce..ea3459709c6 100644
--- a/crates/router/src/core/recon.rs
+++ b/crates/router/src/core/recon.rs
@@ -39,7 +39,8 @@ pub async fn send_recon_request(
         .attach_printable("Failed to convert recipient's email to UserEmail")?,
         settings: state.conf.clone(),
         subject: format!(
-            "Dashboard Pro Feature Request by {}",
+            "{} {}",
+            consts::EMAIL_SUBJECT_DASHBOARD_FEATURE_REQUEST,
             user_email.expose().peek()
         ),
     };
@@ -145,7 +146,7 @@ pub async fn recon_merchant_account_update(
             .change_context(errors::ApiErrorResponse::InternalServerError)
             .attach_printable("Failed to form username")?,
         settings: state.conf.clone(),
-        subject: "Approval of Recon Request - Access Granted to Recon Dashboard",
+        subject: consts::EMAIL_SUBJECT_APPROVAL_RECON_REQUEST,
     };
 
     if req.recon_status == enums::ReconStatus::Active {
diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs
index f36ecc18116..d5a9c143bea 100644
--- a/crates/router/src/core/user.rs
+++ b/crates/router/src/core/user.rs
@@ -75,7 +75,7 @@ pub async fn signup_with_merchant_id(
         recipient_email: user_from_db.get_email().try_into()?,
         user_name: domain::UserName::new(user_from_db.get_name())?,
         settings: state.conf.clone(),
-        subject: "Get back to Hyperswitch - Reset Your Password Now",
+        subject: consts::user::EMAIL_SUBJECT_RESET_PASSWORD,
         auth_id,
     };
 
@@ -204,7 +204,7 @@ pub async fn connect_account(
             recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
             settings: state.conf.clone(),
             user_name: domain::UserName::new(user_from_db.get_name())?,
-            subject: "Unlock Hyperswitch: Use Your Magic Link to Sign In",
+            subject: consts::user::EMAIL_SUBJECT_MAGIC_LINK,
             auth_id,
         };
 
@@ -254,7 +254,7 @@ pub async fn connect_account(
         let email_contents = email_types::VerifyEmail {
             recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
             settings: state.conf.clone(),
-            subject: "Welcome to the Hyperswitch community!",
+            subject: consts::user::EMAIL_SUBJECT_SIGNUP,
             auth_id,
         };
 
@@ -374,7 +374,7 @@ pub async fn forgot_password(
         recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
         settings: state.conf.clone(),
         user_name: domain::UserName::new(user_from_db.get_name())?,
-        subject: "Get back to Hyperswitch - Reset Your Password Now",
+        subject: consts::user::EMAIL_SUBJECT_RESET_PASSWORD,
         auth_id,
     };
 
@@ -702,7 +702,7 @@ async fn handle_existing_user_invitation(
             recipient_email: invitee_email,
             user_name: domain::UserName::new(invitee_user_from_db.get_name())?,
             settings: state.conf.clone(),
-            subject: "You have been invited to join Hyperswitch Community!",
+            subject: consts::user::EMAIL_SUBJECT_INVITATION,
             entity,
             auth_id: auth_id.clone(),
         };
@@ -823,7 +823,7 @@ async fn handle_new_user_invitation(
             recipient_email: invitee_email,
             user_name: domain::UserName::new(new_user.get_name())?,
             settings: state.conf.clone(),
-            subject: "You have been invited to join Hyperswitch Community!",
+            subject: consts::user::EMAIL_SUBJECT_INVITATION,
             entity,
             auth_id: auth_id.clone(),
         };
@@ -942,7 +942,7 @@ pub async fn resend_invite(
         recipient_email: invitee_email,
         user_name: domain::UserName::new(user.get_name())?,
         settings: state.conf.clone(),
-        subject: "You have been invited to join Hyperswitch Community!",
+        subject: consts::user::EMAIL_SUBJECT_INVITATION,
         entity: email_types::Entity {
             entity_id,
             entity_type,
@@ -1823,7 +1823,7 @@ pub async fn send_verification_mail(
     let email_contents = email_types::VerifyEmail {
         recipient_email: domain::UserEmail::from_pii_email(user.email)?,
         settings: state.conf.clone(),
-        subject: "Welcome to the Hyperswitch community!",
+        subject: consts::user::EMAIL_SUBJECT_SIGNUP,
         auth_id,
     };
 
diff --git a/crates/router/src/services/email/types.rs b/crates/router/src/services/email/types.rs
index 1c4ce79ac8c..cedd17828f1 100644
--- a/crates/router/src/services/email/types.rs
+++ b/crates/router/src/services/email/types.rs
@@ -417,7 +417,7 @@ impl BizEmailProd {
                 state.conf.email.prod_intent_recipient_email.clone(),
             )?,
             settings: state.conf.clone(),
-            subject: "New Prod Intent",
+            subject: consts::user::EMAIL_SUBJECT_NEW_PROD_INTENT,
             user_name: data.poc_name.unwrap_or_default().into(),
             poc_email: data.poc_email.unwrap_or_default().into(),
             legal_business_name: data.legal_business_name.unwrap_or_default(),
diff --git a/crates/router/src/workflows/api_key_expiry.rs b/crates/router/src/workflows/api_key_expiry.rs
index b26e9862e81..c04e4c5d576 100644
--- a/crates/router/src/workflows/api_key_expiry.rs
+++ b/crates/router/src/workflows/api_key_expiry.rs
@@ -6,7 +6,7 @@ use router_env::{logger, metrics::add_attributes};
 use scheduler::{workflows::ProcessTrackerWorkflow, SchedulerSessionState};
 
 use crate::{
-    errors,
+    consts, errors,
     logger::error,
     routes::{metrics, SessionState},
     services::email::types::ApiKeyExpiryReminder,
@@ -81,7 +81,7 @@ impl ProcessTrackerWorkflow<SessionState> for ApiKeyExpiryWorkflow {
                 );
                 errors::ProcessTrackerError::EApiErrorResponse
             })?,
-            subject: "API Key Expiry Notice",
+            subject: consts::EMAIL_SUBJECT_API_KEY_EXPIRY,
             expires_in: *expires_in,
             api_key_name,
             prefix,

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [x] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
Change the hardcoded email subject to constants

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables


## Motivation and Context
refactor based on this issue -  #5940 
[link](https://github.com/juspay/hyperswitch/issues/5940)
Closes #5940.

## How did you test it?

This is an internal change for email subjects.

There should be no affect. All email subjects like magic link, invite should be properly sent as before.

[change_apply_before.txt](https://github.com/user-attachments/files/17147768/change_apply_before.txt)
[change_apply_after.txt](https://github.com/user-attachments/files/17147771/change_apply_after.txt)


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
