@@ -65,7 +65,7 @@ class MembershipTarget:
6565def _build_membership_target (membership_request : MembershipRequest ) -> MembershipTarget :
6666 """Resolve the notification target from a membership request."""
6767 if membership_request .target_kind == MembershipRequest .TargetKind .user :
68- user = FreeIPAUser .get (membership_request .requested_username )
68+ user = FreeIPAUser .get (membership_request .requested_username , respect_privacy = False )
6969 return MembershipTarget (
7070 email = user .email if user is not None else "" ,
7171 email_context = user_email_context_from_user (user = user ) if user is not None else {},
@@ -250,8 +250,35 @@ def _send_membership_request_notification(
250250 membership_type : MembershipType ,
251251 template_name : str ,
252252 extra_context : dict [str , object ] | None = None ,
253+ log_context : dict [str , object ] | None = None ,
253254) -> object | None :
254255 if not target .email :
256+ request_id = None
257+ action = "unknown"
258+ if log_context :
259+ request_id = log_context .get ("request_id" )
260+ action = str (log_context .get ("action" ) or action )
261+ warning_extra = {
262+ "event" : "astra.membership.email.skipped_missing_recipient" ,
263+ "component" : "membership" ,
264+ "outcome" : "warning" ,
265+ "template_name" : template_name ,
266+ "target_kind" : "organization" if target .target_organization is not None else "user" ,
267+ "target_username" : target .target_username ,
268+ "target_organization_id" : target .target_organization .pk if target .target_organization is not None else None ,
269+ }
270+ if log_context :
271+ warning_extra .update (log_context )
272+ logger .warning (
273+ "Membership email skipped because recipient email is missing request_id=%s action=%s target_kind=%s target_username=%s target_organization_id=%s template_name=%s" ,
274+ request_id ,
275+ action ,
276+ "organization" if target .target_organization is not None else "user" ,
277+ target .target_username ,
278+ target .target_organization .pk if target .target_organization is not None else None ,
279+ template_name ,
280+ extra = warning_extra ,
281+ )
255282 return None
256283
257284 context : dict [str , object ] = {
@@ -405,7 +432,7 @@ def record_membership_request_created(
405432
406433 if send_submitted_email :
407434 try :
408- target = FreeIPAUser .get (membership_request .requested_username )
435+ target = FreeIPAUser .get (membership_request .requested_username , respect_privacy = False )
409436 except Exception as e :
410437 logger .exception (
411438 "%s: FreeIPAUser.get failed for submitted email request_id=%s target=%r" ,
@@ -440,6 +467,23 @@ def record_membership_request_created(
440467 extra = current_exception_log_fields (),
441468 )
442469 email_error = e
470+ elif target is not None :
471+ logger .warning (
472+ "%s: submitted email skipped due to missing recipient address request_id=%s target=%r" ,
473+ log_prefix ,
474+ membership_request .pk ,
475+ membership_request .requested_username ,
476+ extra = {
477+ "event" : "astra.membership.email.skipped_missing_recipient" ,
478+ "component" : "membership" ,
479+ "outcome" : "warning" ,
480+ "template_name" : settings .MEMBERSHIP_REQUEST_SUBMITTED_EMAIL_TEMPLATE_NAME ,
481+ "request_id" : membership_request .pk ,
482+ "target_kind" : "user" ,
483+ "target_username" : membership_request .requested_username ,
484+ "action" : "submitted" ,
485+ },
486+ )
443487
444488 _try_record_email_note (
445489 membership_request = membership_request ,
@@ -663,6 +707,23 @@ def approve_membership_request(
663707 previous_expires_at = previous_expires_at ,
664708 )
665709 _ensure_configured_email_template_exists (template_name = template_name )
710+ elif send_approved_email :
711+ logger .warning (
712+ "%s: approved email skipped due to missing recipient address request_id=%s org_id=%s" ,
713+ log_prefix ,
714+ membership_request .pk ,
715+ org .pk ,
716+ extra = {
717+ "event" : "astra.membership.email.skipped_missing_recipient" ,
718+ "component" : "membership" ,
719+ "outcome" : "warning" ,
720+ "template_name" : settings .MEMBERSHIP_REQUEST_APPROVED_EMAIL_TEMPLATE_NAME ,
721+ "request_id" : membership_request .pk ,
722+ "target_kind" : "organization" ,
723+ "target_organization_id" : org .pk ,
724+ "action" : "approved" ,
725+ },
726+ )
666727
667728 old_membership = (
668729 Membership .objects .select_related ("membership_type" )
@@ -731,7 +792,7 @@ def approve_membership_request(
731792 )
732793
733794 try :
734- user = FreeIPAUser .get (membership_request .requested_username )
795+ user = FreeIPAUser .get (membership_request .requested_username , respect_privacy = False )
735796 except Exception :
736797 logger .exception (
737798 "%s: FreeIPAUser.get failed request_id=%s target=%r" ,
@@ -759,6 +820,23 @@ def approve_membership_request(
759820 previous_expires_at = previous_expires_at ,
760821 )
761822 _ensure_configured_email_template_exists (template_name = template_name )
823+ elif send_approved_email :
824+ logger .warning (
825+ "%s: approved email skipped due to missing recipient address request_id=%s target=%r" ,
826+ log_prefix ,
827+ membership_request .pk ,
828+ membership_request .requested_username ,
829+ extra = {
830+ "event" : "astra.membership.email.skipped_missing_recipient" ,
831+ "component" : "membership" ,
832+ "outcome" : "warning" ,
833+ "template_name" : settings .MEMBERSHIP_REQUEST_APPROVED_EMAIL_TEMPLATE_NAME ,
834+ "request_id" : membership_request .pk ,
835+ "target_kind" : "user" ,
836+ "target_username" : membership_request .requested_username ,
837+ "action" : "approved" ,
838+ },
839+ )
762840 group_add_payload = (membership_request .requested_username , membership_type .group_cn )
763841
764842 email_context = (
@@ -978,14 +1056,19 @@ def reject_membership_request(
9781056
9791057 email_error : Exception | None = None
9801058 sent_email = None
981- if send_rejected_email and target . email :
1059+ if send_rejected_email :
9821060 try :
9831061 sent_email = _send_membership_request_notification (
9841062 target = target ,
9851063 membership_type = membership_type ,
9861064 template_name = settings .MEMBERSHIP_REQUEST_REJECTED_EMAIL_TEMPLATE_NAME ,
9871065 extra_context = freeform_message_email_context (key = "rejection_reason" , value = reason ),
1066+ log_context = {
1067+ "request_id" : membership_request .pk ,
1068+ "action" : "rejected" ,
1069+ },
9881070 )
1071+
9891072 except Exception as e :
9901073 logger .exception (
9911074 "%s: sending rejected email failed request_id=%s" ,
@@ -1182,6 +1265,10 @@ def put_membership_request_on_hold(
11821265 ** freeform_message_email_context (key = "rfi_message" , value = message ),
11831266 "application_url" : application_url ,
11841267 },
1268+ log_context = {
1269+ "request_id" : membership_request .pk ,
1270+ "action" : "rfi" ,
1271+ },
11851272 )
11861273 except Exception as e :
11871274 logger .exception (
@@ -1191,6 +1278,16 @@ def put_membership_request_on_hold(
11911278 extra = current_exception_log_fields (),
11921279 )
11931280 email_error = e
1281+ elif send_rfi_email :
1282+ _send_membership_request_notification (
1283+ target = target ,
1284+ membership_type = membership_type ,
1285+ template_name = settings .MEMBERSHIP_REQUEST_RFI_EMAIL_TEMPLATE_NAME ,
1286+ log_context = {
1287+ "request_id" : membership_request .pk ,
1288+ "action" : "rfi" ,
1289+ },
1290+ )
11941291
11951292 log = _create_status_change_log (
11961293 membership_request = membership_request ,
0 commit comments