dhisana 0.0.1.dev226__py3-none-any.whl → 0.0.1.dev227__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,14 @@
1
1
  import base64
2
2
  import csv
3
3
  import datetime
4
+ import html as html_lib
4
5
  import io
5
6
  import json
6
7
  import logging
7
8
  import os
8
9
  import re
9
10
  import uuid
11
+ from email.mime.multipart import MIMEMultipart
10
12
  from email.mime.text import MIMEText
11
13
  from typing import Any, Dict, List, Optional
12
14
 
@@ -109,6 +111,28 @@ def get_google_credentials(
109
111
  return credentials
110
112
 
111
113
 
114
+ def _looks_like_html(text: str) -> bool:
115
+ """Heuristically determine whether the body contains HTML markup."""
116
+ return bool(text and re.search(r"<[a-zA-Z][^>]*>", text))
117
+
118
+
119
+ def _html_to_plain_text(html: str) -> str:
120
+ """
121
+ Produce a very lightweight plain-text version of an HTML fragment.
122
+ This keeps newlines on block boundaries and strips tags.
123
+ """
124
+ if not html:
125
+ return ""
126
+ text = re.sub(r"(?is)<(script|style).*?>.*?</\1>", " ", html)
127
+ text = re.sub(r"(?i)<br\s*/?>", "\n", text)
128
+ text = re.sub(r"(?i)</(p|div|li|h[1-6])\s*>", "\n", text)
129
+ text = re.sub(r"(?is)<.*?>", "", text)
130
+ text = html_lib.unescape(text)
131
+ text = re.sub(r"\s+\n", "\n", text)
132
+ text = re.sub(r"\n{3,}", "\n\n", text)
133
+ return text.strip()
134
+
135
+
112
136
 
113
137
  @assistant_tool
114
138
  async def send_email_using_service_account_async(
@@ -137,8 +161,16 @@ async def send_email_using_service_account_async(
137
161
 
138
162
  gmail_api_url = 'https://gmail.googleapis.com/gmail/v1/users/me/messages/send'
139
163
 
140
- # Construct the MIME text message
141
- message = MIMEText(send_email_context.body)
164
+ body = send_email_context.body or ""
165
+
166
+ if _looks_like_html(body):
167
+ # Gmail prefers multipart/alternative when HTML is present.
168
+ message = MIMEMultipart("alternative")
169
+ message.attach(MIMEText(_html_to_plain_text(body), "plain", _charset="utf-8"))
170
+ message.attach(MIMEText(body, "html", _charset="utf-8"))
171
+ else:
172
+ message = MIMEText(body, _subtype="plain", _charset="utf-8")
173
+
142
174
  message['to'] = send_email_context.recipient
143
175
  message['from'] = f"{send_email_context.sender_name} <{send_email_context.sender_email}>"
144
176
  message['subject'] = send_email_context.subject
@@ -1186,4 +1218,3 @@ def save_values_to_csv(values: List[List[str]], output_filename: str) -> str:
1186
1218
  writer.writerows(values)
1187
1219
 
1188
1220
  return local_file_path
1189
-
@@ -7,12 +7,14 @@ import datetime
7
7
  import email
8
8
  import email.utils
9
9
  import hashlib
10
+ import html as html_lib
10
11
  import imaplib
11
12
  import logging
12
13
  import re
13
14
  import uuid
14
15
  from email.errors import HeaderParseError
15
16
  from email.header import Header, decode_header, make_header
17
+ from email.mime.multipart import MIMEMultipart
16
18
  from email.mime.text import MIMEText
17
19
  from datetime import datetime, timedelta, timezone
18
20
  from typing import Any, Dict, List, Optional, Union
@@ -102,6 +104,28 @@ def _to_datetime(val: Union[datetime, str]) -> datetime:
102
104
  ) from exc
103
105
 
104
106
 
107
+ def _looks_like_html(text: str) -> bool:
108
+ """Heuristically determine whether the body contains HTML markup."""
109
+ return bool(text and re.search(r"<[a-zA-Z][^>]*>", text))
110
+
111
+
112
+ def _html_to_plain_text(html: str) -> str:
113
+ """
114
+ Produce a very lightweight plain-text version of an HTML fragment.
115
+ This keeps newlines on block boundaries and strips tags.
116
+ """
117
+ if not html:
118
+ return ""
119
+ text = re.sub(r"(?is)<(script|style).*?>.*?</\1>", " ", html)
120
+ text = re.sub(r"(?i)<br\s*/?>", "\n", text)
121
+ text = re.sub(r"(?i)</(p|div|li|h[1-6])\s*>", "\n", text)
122
+ text = re.sub(r"(?is)<.*?>", "", text)
123
+ text = html_lib.unescape(text)
124
+ text = re.sub(r"\s+\n", "\n", text)
125
+ text = re.sub(r"\n{3,}", "\n\n", text)
126
+ return text.strip()
127
+
128
+
105
129
  # --------------------------------------------------------------------------- #
106
130
  # Outbound -- SMTP
107
131
  # --------------------------------------------------------------------------- #
@@ -127,7 +151,16 @@ async def send_email_via_smtp_async(
127
151
  str
128
152
  The Message-ID of the sent message (e.g., "<uuid@yourdomain.com>").
129
153
  """
130
- msg = MIMEText(ctx.body, _charset="utf-8")
154
+ body = ctx.body or ""
155
+
156
+ if _looks_like_html(body):
157
+ # Build multipart/alternative so HTML-capable clients see rich content.
158
+ msg = MIMEMultipart("alternative")
159
+ msg.attach(MIMEText(_html_to_plain_text(body), "plain", _charset="utf-8"))
160
+ msg.attach(MIMEText(body, "html", _charset="utf-8"))
161
+ else:
162
+ msg = MIMEText(body, _subtype="plain", _charset="utf-8")
163
+
131
164
  msg["From"] = f"{ctx.sender_name} <{ctx.sender_email}>"
132
165
  msg["To"] = ctx.recipient
133
166
  msg["Subject"] = ctx.subject
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev226
3
+ Version: 0.0.1.dev227
4
4
  Summary: A Python SDK for Dhisana AI Platform
5
5
  Home-page: https://github.com/dhisana-ai/dhisana-python-sdk
6
6
  Author: Admin
@@ -46,7 +46,7 @@ dhisana/utils/generate_linkedin_response_message.py,sha256=udAt4V_vNuieyyfhrtTFW
46
46
  dhisana/utils/generate_structured_output_internal.py,sha256=83SaThDAa_fANJEZ5CSCMcPpD_MN5zMI9NU1uEtQO2E,20705
47
47
  dhisana/utils/google_custom_search.py,sha256=5rQ4uAF-hjFpd9ooJkd6CjRvSmhZHhqM0jfHItsbpzk,10071
48
48
  dhisana/utils/google_oauth_tools.py,sha256=cYynzqRgv79aPMK8DehrXUyAPReO3hyDJiJ8-1008XM,25232
49
- dhisana/utils/google_workspace_tools.py,sha256=22mmJ2KyJAx4Ewo_AK2qDLF5veYcB7sWcb00vw21qhM,44727
49
+ dhisana/utils/google_workspace_tools.py,sha256=UVxEicpPsm_DfadXygp6ELzXuVfFv9cVSaQrQwFoxqM,45898
50
50
  dhisana/utils/hubspot_clearbit.py,sha256=keNX1F_RnDl9AOPxYEOTMdukV_A9g8v9j1fZyT4tuP4,3440
51
51
  dhisana/utils/hubspot_crm_tools.py,sha256=lbXFCeq690_TDLjDG8Gm5E-2f1P5EuDqNf5j8PYpMm8,99298
52
52
  dhisana/utils/instantly_tools.py,sha256=hhqjDPyLE6o0dzzuvryszbK3ipnoGU2eBm6NlsUGJjY,4771
@@ -77,7 +77,7 @@ dhisana/utils/serpapi_search_tools.py,sha256=MglMPN9wHkGAHb7YAQXvEDsWK3RGS-zu3wU
77
77
  dhisana/utils/serperdev_google_jobs.py,sha256=m5_2f_5y79FOFZz1A_go6m0hIUfbbAoZ0YTjUMO2BSI,4508
78
78
  dhisana/utils/serperdev_local_business.py,sha256=JoZfTg58Hojv61cyuwA2lcnPdLT1lawnWaBNrUYWnuQ,6447
79
79
  dhisana/utils/serperdev_search.py,sha256=_iBKIfHMq4gFv5StYz58eArriygoi1zW6VnLlux8vto,9363
80
- dhisana/utils/smtp_email_tools.py,sha256=kx0VSa0JQyVLD020oARCHhOBZJxDwMIri1Z7jPN0nP4,15843
80
+ dhisana/utils/smtp_email_tools.py,sha256=yWg5BmQgRfnHiID7waHkq2sCNuCFBHe0-uVFgWtlr7c,17035
81
81
  dhisana/utils/test_connect.py,sha256=wkswcwEyMSVhZACHtqsZDhP6QpDMW4wq5MTcfRokvOM,69021
82
82
  dhisana/utils/trasform_json.py,sha256=s48DoyzVVCI4dTvSUwF5X-exX6VH6nPWrjbUENkYuNE,6979
83
83
  dhisana/utils/web_download_parse_tools.py,sha256=ouXwH7CmjcRjoBfP5BWat86MvcGO-8rLCmWQe_eZKjc,7810
@@ -92,8 +92,8 @@ dhisana/workflow/agent.py,sha256=esv7_i_XuMkV2j1nz_UlsHov_m6X5WZZiZm_tG4OBHU,565
92
92
  dhisana/workflow/flow.py,sha256=xWE3qQbM7j2B3FH8XnY3zOL_QXX4LbTW4ArndnEYJE0,1638
93
93
  dhisana/workflow/task.py,sha256=HlWz9mtrwLYByoSnePOemBUBrMEcj7KbgNjEE1oF5wo,1830
94
94
  dhisana/workflow/test.py,sha256=kwW8jWqSBNcRmoyaxlTuZCMOpGJpTbJQgHI7gSjwdzM,3399
95
- dhisana-0.0.1.dev226.dist-info/METADATA,sha256=YmfqrcE8RzTAkcZzrVyJHN3-LOZpCcCTgbw8Lqq1wYA,1190
96
- dhisana-0.0.1.dev226.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
97
- dhisana-0.0.1.dev226.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
98
- dhisana-0.0.1.dev226.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
99
- dhisana-0.0.1.dev226.dist-info/RECORD,,
95
+ dhisana-0.0.1.dev227.dist-info/METADATA,sha256=xJCNdyGsigROGAFmkncnMU5ogDb2sScbvmOmCfTh1SQ,1190
96
+ dhisana-0.0.1.dev227.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
97
+ dhisana-0.0.1.dev227.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
98
+ dhisana-0.0.1.dev227.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
99
+ dhisana-0.0.1.dev227.dist-info/RECORD,,