Ë
    qýuj�*  ã                   óž  — d Z ddlZddlZddlZddlZddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZmZmZmZmZmZmZ dd	lmZmZ dd
lmZmZ  ej8                  e«      Z ej>                  d«      Z ddddœZ! G d„ de"«      Z#de$de%fd„Z&de%fd„Z'	 	 d$de$de$de$de$de(de$fd„Z)d„ Z*de$de$fd„Z+de$de$fd „Z,	 d%d!e$de$d"e$de$de$de(fd#„Z-y)&a¨  Outbound email for the chatbot.

Deliberately provider-agnostic: the chat layer calls send_email() and never
knows how it is delivered. Today that is SMTP; swapping in Mailchimp
Transactional (Mandrill) or Azure Communication Services later means adding a
branch here, not touching the tool or the prompt.

Email bodies are always composed by the caller from knowledge-base content --
this module only formats and delivers.
é    N)Údatetime)ÚEmailMessage)Ú
formataddr)Úsettings)Úbrand_for_tenant)Ú	CTA_BLOCKÚDISCLAIMER_BLOCKÚEMAIL_TEMPLATEÚIMAGE_SHELLÚLINKS_BLOCKÚ	LOGO_CELLÚUNSUBSCRIBE_BLOCK)Úgenerate_body_imageÚimage_generation_available)Úget_email_settingsÚrender_placeholdersz^[^@\s]+@[^@\s]+\.[a-zA-Z]{2,}$z&Thanks for chatting with {{brandName}}u6   Â© {{currentYear}} {{brandName}}. All rights reserved.zzResponses are powered by AI and may contain errors or omissions. Please verify important information before relying on it.)ÚheaderÚfooterÚaiDisclaimerc                   ó   — e Zd ZdZy)ÚEmailNotConfiguredz>Raised when email is requested but no transport is configured.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    ú9/var/www/html/strategist-ai/app/services/email_service.pyr   r   +   s   „ ÚHr   r   ÚaddressÚreturnc                 ób   — t        | xr# t        j                  | j                  «       «      «      S ©N)ÚboolÚEMAIL_REÚmatchÚstrip)r   s    r   Úis_valid_emailr'   /   s!   € Ü�Ò;œHŸN™N¨7¯=©=«?Ó;Ó<Ð<r   c                  ó    — t        t        j                  xr4 t        j                  xr" t        j                  xr t        j
                  «      S r"   )r#   r   ÚEMAIL_ENABLEDÚ	SMTP_HOSTÚ
SMTP_EMAILÚ	SMTP_PASSr   r   r   Úemail_configuredr-   3   sD   € ÜÜ×Ñò 	Ü×Ñò	ä×Ñò	ô ×Ñó	ð r   ÚsubjectÚ	body_htmlÚ
first_nameÚ	tenant_idÚsettings_overridec                 ó<  ‡‡— t        |«      Š|r|xs t        |«      nt        }t        t	        j
                  «       j                  «      Šˆˆfd„}d}|j                  d«      xs dj                  «       rt        j                  d ||d   «      «      }‰j                  r,‰j                  r t        j                  d‰j                  «      nd}‰j                  r,‰j                  r t!        j                  d‰j                  «      nd}	d}
‰j"                  rCt%        j                  d‰j"                  «      j                  dt'        ‰j(                  «      «      }
t'        |xs dj                  «       j+                  d	«      d
   «      xs d}t,        }t'        | «      t'        ‰j(                  «      |||
|
rdnd ||j                  d«      xs d«       ||j                  d«      xs d«      |||	dœj/                  «       D ]  \  }}|j                  ||«      }Œ |S )z@Fill the branded template using this tenant's branding and copy.c                 óD   •— t        t        | ‰j                  ‰«      «      S r"   ©Ú_escaper   Úname©ÚtextÚbrandÚyears    €€r   Úfillz_render_html.<locals>.fillC   s   ø€ ÜÔ*¨4°·±¸TÓBÓCÐCr   Ú r   ú{disclaimerText}z{chatbotUrl}z{unsubscribeUrl}ú	{logoUrl}ú{brandName}Ú r   Útherez style="padding-left: 12px;"r   r   )ú	{subject}r@   ú{firstName}z{generatedAnswer}ú
{logoCell}ú{brandCellPad}ú{headerText}ú{footerText}z{disclaimerBlock}z
{ctaBlock}z{unsubscribeBlock})r   r   ÚDEFAULT_COPYÚstrr   Únowr;   Úgetr&   r	   ÚreplaceÚshow_ctaÚchatbot_urlr   Úshow_unsubscribeÚunsubscribe_urlr   Úlogo_urlr   r6   r7   Úsplitr
   Úitems)r.   r/   r0   r1   r2   Úcopyr<   Ú
disclaimerÚctaÚunsubscribeÚ	logo_cellÚgreetingÚhtmlÚkeyÚvaluer:   r;   s                  @@r   Ú_render_htmlr^   <   sæ  ù€ ô ˜YÓ'€EÙAJÐÒ=Ô 2°9Ô =ÔP\€DÜŒx�|‰|‹~×"Ñ"Ó#€DõDð €JØ�‰�Ó Ò& B×-Ñ-Ô/Ü%×-Ñ-Ð.@Á$ÀtÈNÑG[ÓB\Ó]ˆ
ð 	�Š˜5×,Ò,ô ×
Ñ
˜N¨E×,=Ñ,=Ô
>Ø35ð ð 	×Ò 5×#8Ò#8ô $×+Ñ+Ð,>À×@UÑ@UÔVØ?Að ð
 €IØ‡~‚~Ü×%Ñ% k°5·>±>ÓB×JÑJØœ7 5§:¡:Ó.ó0ˆ	ô ˜
Ò( b×/Ñ/Ó1×7Ñ7¸Ó<¸QÑ?Ó@ÒKÀG€Hä€Dä˜WÓ%Ü˜uŸz™zÓ*ØØ&ØÙ<EÑ8È2Ù˜TŸX™X hÓ/Ò5°2Ó6Ù˜TŸX™X hÓ/Ò5°2Ó6Ø'ØØ)ñ÷ �eƒgò(‰
ˆˆUð �|‰|˜C Ó'‰ð(ð €Kr   c                 ód  ‡‡— t        t        j                  «       j                  «      Šˆˆfd„}d}‰j                  rCt        j                  d‰j                  «      j                  dt        ‰j                  «      «      }d}|rdj                  ˆfd„|dd D «       «      }t        }	t        | «      t        ‰j                  «      t        |xs dj                  «       j                  d	«      d
   «      xs d ||j                  d«      «       ||j                  d«      «       ||j                  d«      «      |t        | «      ‰j                  xs d‰j                  xs ddz   ||rdnd|rt        j                  d|«      nddœj!                  «       D ]  \  }
}|	j                  |
|«      }	Œ |	S )z˜HTML around a generated body image. Links stay real HTML so they remain
    clickable, and the footer keeps enough text that the mail is not image-only.c                 óL   •— t        t        | xs d‰j                  ‰«      «      S )Nr=   r5   r8   s    €€r   r<   z!_render_image_shell.<locals>.fillq   s    ø€ ÜÔ*¨4ª:°2°u·z±zÀ4ÓHÓIÐIr   r=   r?   r@   u    &nbsp;Â·&nbsp; c              3   ó¤   •K  — | ]G  }d |› d‰j                   xs d› dt        |j                  dd«      j                  dd«      «      › d�–— ŒI y­w)	z	<a href="z" style="color:ú#4B4B8Fz;text-decoration:underline;">zhttps://r=   zhttp://z</a>N)Úprimary_colorr6   rM   )Ú.0Úur:   s     €r   ú	<genexpr>z&_render_image_shell.<locals>.<genexpr>{   se   øè ø€ ò -
ð ð ˜�s˜/¨%×*=Ñ*=Ò*JÀÐ)Kð L+Ü+2°1·9±9¸ZÈÓ3L×3TÑ3TÐU^Ð`bÓ3cÓ+dÐ*eÐeiôkñ-
ùs   ƒAANé   rA   r   rB   r   r   r   rb   Ú14z style="padding-left:12px;"z{linkItems})rC   r@   rD   rG   rH   r>   z{bodyImageUrl}z
{imageAlt}z{primaryColor}z{headerTint}rE   rF   z{linksBlock})rJ   r   rK   r;   rR   r   rM   r6   r7   Újoinr   r&   rS   rL   rc   r   rT   )r.   Ú	image_urlr:   rU   r0   Úlinksr<   rY   Ú
link_itemsr[   r\   r]   r;   s     `         @r   Ú_render_image_shellrm   l   s‰  ù€ ô Œx�|‰|‹~×"Ñ"Ó#€DõJð €IØ‡~‚~Ü×%Ñ% k°5·>±>ÓB×JÑJØœ7 5§:¡:Ó.ó0ˆ	ð €JÙØ'×,Ñ,ó -
ð ˜2˜A�Yô-
ó 
ˆ
ô €Dä˜WÓ%Ü˜uŸz™zÓ*Ü 
Ò 0¨b×7Ñ7Ó9×?Ñ?ÀÓDÀQÑGÓHÒSÈGÙ˜TŸX™X hÓ/Ó0Ù˜TŸX™X hÓ/Ó0Ù  §¡¨.Ó!9Ó:Ø#Ü˜gÓ&Ø×-Ñ-Ò:°Ø×,Ñ,Ò9°	¸TÑAØÙ;DÑ7È"ÙJTœ×+Ñ+¨M¸:ÔFÐZ\ñ÷ �eƒgò(‰
ˆˆUð �|‰|˜C Ó'‰ð(ð  €Kr   r9   c                 óv  ‡‡— g Šg Šˆˆfd„}| xs dj                  d«      D ]~  }|j                  «       }|s |«        Œ|j                  d«      r,‰j                  t	        |dd j                  «       «      «       ŒZ |«        ‰j                  dt	        |«      › d�«       Œ€  |«        dj                  ‰«      S )	zDTurn the model's plain-text body into simple paragraphs and bullets.c                  ó†   •— ‰r>dj                  d„ ‰D «       «      } ‰j                  d| › d�«       ‰j                  «        y y )Nr=   c              3   ó(   K  — | ]
  }d |› d�–— Œ y­w)z<li style='margin:4px 0;'>z</li>Nr   )rd   Úbs     r   rf   z7_text_to_html.<locals>.flush_bullets.<locals>.<genexpr>œ   s   è ø€ ÒSÀaÐ8¸¸¸5ÔAÑSùs   ‚z-<ul style='margin:12px 0;padding-left:20px;'>z</ul>)ri   ÚappendÚclear)rT   ÚbulletsÚ
html_partss    €€r   Úflush_bulletsz$_text_to_html.<locals>.flush_bulletsš   sA   ø€ ÙØ—G‘GÑSÈ7ÔSÓSˆEØ×ÑÐ MÈeÈWÐTYÐZÔ[Ø�M‰M�Oð r   r=   Ú
)z- z* u   â€¢ é   Nz<p style='margin:12px 0;'>z</p>)rS   r&   Ú
startswithrr   r6   ri   )r9   rv   ÚrawÚlinert   ru   s       @@r   Ú_text_to_htmlr|   •   s¬   ù€ à€JØ€Gõð ’
˜×!Ñ! $Ó'ò 	PˆØ�y‰y‹{ˆÙÙŒOØØ�?‰?Ð/Ô0Ø�N‰Nœ7 4¨¨ 8§>¡>Ó#3Ó4Õ5áŒOØ×ÑÐ :¼7À4»=¸/ÈÐNÕOð	Pñ „OØ�7‰7�:ÓÐr   Úsc                 óf   — | j                  dd«      j                  dd«      j                  dd«      S )Nú&z&amp;Ú<z&lt;Ú>z&gt;)rM   )r}   s    r   r6   r6   ®   s-   € Ø�I‰I�c˜7Ó#×+Ñ+¨C°Ó8×@Ñ@ÀÀfÓMÐNr   Ú
to_addressÚ	body_textc                 ó
  — t        «       st        j                  d«       dddœS |r9t        |«      j	                  dd«      st        j                  d|› d�«       dd	dœS | xs d
j                  «       } t        | «      s	dd| › d�dœS |xs d
j                  «       xs dt        j                  › �}t        j                  xs t        j                  }t        «       }||d<   t        t        j                  |f«      |d<   | |d<   t        |«      }|j                  r|j                  |d<   |j!                  |xs d
«       |rt        |«      nt"        }d}	t%        «       r?t'        |||xs d
|¬«      }
|
r*t)        ||
d   |||t+        |j,                  xs g «      «      }	|	s-t        j                  d«       t/        |t1        |«      |||«      }	|j3                  |	d¬«       	 t        j4                  r’t7        j8                  «       }t;        j<                  t        j>                  t        j@                  |d¬«      5 }|jC                  t        j                  t        jD                  «       |jG                  |«       ddd«       n t;        jH                  t        j>                  t        j@                  d¬«      5 }|jK                  t7        j8                  «       ¬«       |jC                  t        j                  t        jD                  «       |jG                  |«       ddd«       d"jQ                  |xs d
jS                  «       «      dd# }t        jU                  d$| › d%|›d&tW        |xs d
«      › d'|›�«       d(| |d)œS # 1 sw Y   ŒcxY w# 1 sw Y   ŒoxY w# t:        jL                  $ r'}t        j                  d|› �«       dddœcY d}~S d}~wtN        $ r,}t        j                  d| › d|› �d¬ «       dd!dœcY d}~S d}~ww xY w)*zäSend one email. Returns a result dict; never raises for delivery failure.

    body_text is plain text (as written by the model from knowledge-base
    content); it is rendered to simple HTML and also sent as the text part.
    zEsend_email called but email is not configured (EMAIL_ENABLED/SMTP_*).Úerrorz(Email is not configured on this service.)ÚstatusÚdetailÚenabledTzBlocked outbound email for z: emailing is disabled.z)Emailing is turned off for this business.r=   ú'z' is not a valid email address.zInformation from ÚSubjectÚFromÚTozReply-ToN)r:   r.   rƒ   r1   Úurlz<Body image unavailable; falling back to the static template.r[   )Úsubtypeé   )ÚcontextÚtimeout)r‘   )r�   zSMTP authentication failed: z$Email service authentication failed.zFailed to send email to z: )Úexc_infozCould not send the email.rA   i,  zEMAIL SENT | to=z | subject=z	 | chars=z | body=Úsent)r†   Útor.   ),r-   Úloggerr…   r   rL   Úwarningr&   r'   r   ÚEMAIL_FROM_NAMEÚ
EMAIL_FROMr+   r   r   r   Úreply_toÚset_contentrI   r   r   rm   ÚlistÚreference_linksr^   r|   Úadd_alternativeÚSMTP_SECUREÚsslÚcreate_default_contextÚsmtplibÚSMTP_SSLr*   Ú	SMTP_PORTÚloginr,   Úsend_messageÚSMTPÚstarttlsÚSMTPAuthenticationErrorÚ	Exceptionri   rS   ÚinfoÚlen)r‚   r.   rƒ   r0   r1   ÚsenderÚmsgr:   rU   r[   Úimager�   ÚserverÚexÚpreviews                  r   Ú
send_emailr²   ²   s   € ô ÔÜ�‰Ð\Ô]Ø!Ð-WÑXÐXñ Ô+¨IÓ6×:Ñ:¸9ÀdÔKÜ�‰Ð4°Y°KÐ?VÐWÔXØ!Ð-XÑYÐYàÒ" ×)Ñ)Ó+€JÜ˜*Ô%Ø!¨q°°Ð<[Ð-\Ñ]Ð]àŠ}˜"×#Ñ#Ó%ÒWÐ+<¼X×=UÑ=UÐ<VÐ)W€GÜ× Ñ Ò7¤H×$7Ñ$7€Fä
‹.€CØ€Cˆ	�NÜœh×6Ñ6¸Ð?Ó@€Cˆ�KØ€Cˆ�IÜ˜YÓ'€EØ‡~‚~ØŸ.™.ˆˆJ‰Ø‡O�O�I’O Ô$ñ -6Ô˜iÔ(¼<€DØ€Dô "Ô#Ü#¨%¸Ø.7ªo¸2ÈôTˆáÜ& w°°e±¸eÀTÈ:Ü'+¨E×,AÑ,AÒ,GÀRÓ'HóJˆDñ
 Ü�‰ÐUÔVÜ˜G¤]°9Ó%=¸zÈ9ÐVZÓ[ˆØ×Ñ˜ fÐÔ-ðJÜ×ÒÜ×0Ñ0Ó2ˆGÜ×!Ñ!¤(×"4Ñ"4´h×6HÑ6HØ*1¸2ô?ð )ØBHØ—‘œX×0Ñ0´(×2DÑ2DÔEØ×#Ñ# CÔ(÷)ð )ô
 —‘œh×0Ñ0´(×2DÑ2DÈbÔQð )ÐU[Ø—‘¬×(BÑ(BÓ(D�ÔEØ—‘œX×0Ñ0´(×2DÑ2DÔEØ×#Ñ# CÔ(÷)ð �h‰h˜	š R×.Ñ.Ó0Ó1°$°3Ð7€GÜ
‡K�KØ
˜:˜, k°'°ð =Ü�Y’_ "Ó%Ð& h¨w¨kð	;ôð  J¸7ÑCÐC÷-)ð )ú÷
)ð )ûô ×*Ñ*ò UÜ�‰Ð3°B°4Ð8Ô9Ø!Ð-SÑTÕTûÜò JÜ�‰Ð/°
¨|¸2¸b¸TÐBÈTˆÔRØ!Ð-HÑIÕIûðJúsc   Ç!AN È:A M=É:=N Ê7A$N	ÌN Í=NÎN Î	NÎN ÎPÎ(O
ÏPÏ
PÏ!O=Ï7PÏ=P)NNN)NN).r   ÚloggingÚrer¡   rŸ   r   Úemail.messager   Úemail.utilsr   Úapp.core.configr   Úapp.core.email_brandingr   Úapp.core.email_templater   r	   r
   r   r   r   r   Úapp.services.email_imager   r   Úapp.services.tools_settingsr   r   Ú	getLoggerr   r•   Úcompiler$   rI   r©   r   rJ   r#   r'   r-   Údictr^   rm   r|   r6   r²   r   r   r   ú<module>r¿      sW  ðñ	ó Û 	Û Û 
Ý Ý &Ý "å $Ý 4÷÷ ñ ÷ Uß Oà	ˆ×	Ñ	˜8Ó	$€ð ˆ2�:‰:Ð8Ó9€ð 7ØFðQñ€ôI˜ô Ið=˜Cð = Dó =ð˜$ó ð BFØBFñ,˜#ð ,¨#ð ,¸3ð ,Øð,Ø;?ð,ØKNó,ò`&ðR˜ð  ó ð2Oˆsð O�só Oð
 9=ñQD˜3ð QD¨ð QD¸ð QDØðQDØ25ðQDØAEôQDr   