Ë
    ÿ�já(  ã                   ó˜  — d 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	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 dd	lmZmZ  ej2                  e«      Z ej8                  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"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.

Mailchimp Transactional (Mandrill) is the only delivery path. A tenant must
have an active Mailchimp connection (app/services/integrations/mailchimp.py)
to send email at all -- there is no shared-SMTP fallback. That fallback used
to send every tenant's mail from one global address regardless of which
tenant it was for, which is exactly the identity mix-up this module now
avoids by requiring each tenant to send from their own connected account.
A tenant with no connection, or whose connection fails (revoked key,
Mandrill outage), gets that failure back rather than a silent send under a
different identity.

Email bodies are always composed by the caller from knowledge-base content --
this module only formats and delivers.
é    N)Údatetime)Ú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_placeholders)Úget_mailchimp_connectionÚsend_via_mandrillz^[^@\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__© ó    ú;/var/www/html/strategist-ai/app/services/messaging/email.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'   1   s!   € Ü�Ò;œHŸN™N¨7¯=©=«?Ó;Ó<Ð<r   Ú	tenant_idc                 ó   — | syt        | «      S )z3This tenant's active Mailchimp connection, or None.N)r   ©r(   s    r   Ú_mailchimp_connection_forr+   5   s   € áØÜ# IÓ.Ð.r   c                 ó*   — t        t        | «      «      S r"   )r#   r+   r*   s    r   Úemail_configuredr-   <   s   € ÜÔ)¨)Ó4Ó5Ð5r   ÚsubjectÚ	body_htmlÚ
first_nameÚ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>.fillG   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   r5   r6   Úsplitr   Úitems)r.   r/   r0   r(   r1   Úcopyr;   Ú
disclaimerÚctaÚunsubscribeÚ	logo_cellÚgreetingÚhtmlÚkeyÚvaluer9   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<   r4   r7   s    €€r   r;   z!_render_image_shell.<locals>.fillu   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_colorr5   rL   )Ú.0Úur9   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é   r@   r   rA   r   r   r   ra   Ú14z style="padding-left:12px;"z{linkItems})rB   r?   rC   rF   rG   r=   z{bodyImageUrl}z
{imageAlt}z{primaryColor}z{headerTint}rD   rE   z{linksBlock})rI   r   rJ   r:   rQ   r   rL   r5   r6   Újoinr	   r&   rR   rK   rb   r
   rS   )r.   Ú	image_urlr9   rT   r0   Úlinksr;   rX   Ú
link_itemsrZ   r[   r\   r:   s     `         @r   Ú_render_image_shellrl   p   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   r8   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   )rc   Úbs     r   re   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>)rh   ÚappendÚclear)rS   Ú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>)rR   r&   Ú
startswithrq   r5   rh   )r8   ru   ÚrawÚliners   rt   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;)rL   )r|   s    r   r5   r5   ²   s-   € Ø�I‰I�c˜7Ó#×+Ñ+¨C°Ó8×@Ñ@ÀÀfÓMÐNr   Ú
to_addressÚ	body_textc                 ó¸  — t        |«      st        j                  d|› 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        |«      }|rt        |«      nt        }d}t        «       r?t        |||xs d|¬«      }|r*t        ||d   |||t        |j                   xs g «      «      }|s-t        j                  d«       t#        |t%        |«      |||«      }t'        |«      }	t)        |	| ||xs d||j*                  ¬«      }
|
d   dk7  r|
S dj-                  |xs dj/                  «       «      dd }t        j1                  d| › d|›dt3        |xs d«      › d|›�«       d| |dœS )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.
    zsend_email called for z' but no Mailchimp connection is active.Úerrorz!Connect Mailchimp to send emails.)Ú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 N)r9   r.   r‚   r(   Úurlz<Body image unavailable; falling back to the static template.)Úreply_tor…   Úsentr@   i,  zEMAIL SENT | to=z | subject=z	 | chars=z | body=)r…   Útor.   )r-   Úloggerr„   r   rK   Úwarningr&   r'   r   ÚEMAIL_FROM_NAMEr   rH   r   r   rl   ÚlistÚreference_linksr]   r{   r+   r   rŠ   rh   rR   ÚinfoÚlen)r�   r.   r‚   r0   r(   r9   rT   rZ   ÚimageÚ	mailchimpÚresultÚpreviews               r   Ú
send_emailr˜   ¶   s  € ô ˜IÔ&Ü�‰Ð-¨i¨[Ð8_Ð`ÔaØ!Ð-PÑQÐQñ Ô+¨IÓ6×:Ñ:¸9ÀdÔKÜ�‰Ð4°Y°KÐ?VÐWÔXØ!Ð-XÑYÐYàÒ" ×)Ñ)Ó+€JÜ˜*Ô%Ø!¨q°°Ð<[Ð-\Ñ]Ð]àŠ}˜"×#Ñ#Ó%ÒWÐ+<¼X×=UÑ=UÐ<VÐ)W€GÜ˜YÓ'€Eñ -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Ó[ˆô
 *¨)Ó4€IÜ˜y¨*°g¸yºÈBÐPTØ(-¯©ô8€FàˆhÑ˜6Ò!Øˆð �h‰h˜	š R×.Ñ.Ó0Ó1°$°3Ð7€GÜ
‡K�KØ
˜:˜, k°'°ð =Ü�Y’_ "Ó%Ð& h¨w¨kð	;ôð  J¸7ÑCÐCr   r"   )NNN)NN),r   ÚloggingÚrer   Úapp.core.configr   Úapp.core.email_brandingr   Úapp.core.email_templater   r   r   r	   r
   r   r   Ú"app.services.messaging.email_imager   r   Ú app.services.chat.tools_settingsr   r   Ú#app.services.integrations.mailchimpr   r   Ú	getLoggerr   r�   Úcompiler$   rH   Ú	Exceptionr   rI   r#   r'   r+   r-   Údictr]   rl   r{   r5   r˜   r   r   r   ú<module>r¥      sZ  ðñó Û 	Ý å $Ý 4÷÷ ñ ÷ _ß Tß [à	ˆ×	Ñ	˜8Ó	$€ð ˆ2�:‰:Ð8Ó9€ð 7ØFðQñ€ôI˜ô Ið=˜Cð = Dó =ð/¨ó /ñ6 ð 6¨tó 6ð BFØBFñ,˜#ð ,¨#ð ,¸3ð ,Øð,Ø;?ð,ØKNó,ò`&ðR˜ð  ó ð2Oˆsð O�só Oð
 9=ñ=D˜3ð =D¨ð =D¸ð =DØð=DØ25ð=DØAEô=Dr   