dhisana 0.0.1.dev265__py3-none-any.whl → 0.0.1.dev266__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.
@@ -124,9 +124,12 @@ async def send_email_async(
124
124
 
125
125
  Returns whatever the underlying provider helper returns:
126
126
 
127
+ * Mailgun → str (message-id from Mailgun)
128
+ * SendGrid → str (X-Message-Id from SendGrid)
127
129
  * SMTP → str (Message-ID)
128
130
  * Microsoft 365 → str (message-id)
129
131
  * Google Workspace → str (message-id)
132
+ * Google OAuth → str (message-id)
130
133
  """
131
134
  # ------------------------------------------------------------------ #
132
135
  # 1) Try the preferred providers in order
@@ -1,4 +1,3 @@
1
- import asyncio
2
1
  import logging
3
2
  import os
4
3
  from typing import Optional, List, Dict
@@ -21,7 +20,7 @@ def get_mailgun_notify_key(tool_config: Optional[List[Dict]] = None) -> str:
21
20
  if tool_config:
22
21
  cfg = next((item for item in tool_config if item.get("name") == "mailgun"), None)
23
22
  if cfg:
24
- cfg_map = {i["name"]: i["value"] for i in cfg.get("configuration", []) if i}
23
+ cfg_map = {i.get("name"): i.get("value") for i in cfg.get("configuration", []) if i}
25
24
  key = cfg_map.get("apiKey")
26
25
  key = key or os.getenv("MAILGUN_NOTIFY_KEY")
27
26
  if not key:
@@ -43,7 +42,7 @@ def get_mailgun_notify_domain(tool_config: Optional[List[Dict]] = None) -> str:
43
42
  if tool_config:
44
43
  cfg = next((item for item in tool_config if item.get("name") == "mailgun"), None)
45
44
  if cfg:
46
- cfg_map = {i["name"]: i["value"] for i in cfg.get("configuration", []) if i}
45
+ cfg_map = {i.get("name"): i.get("value") for i in cfg.get("configuration", []) if i}
47
46
  domain = cfg_map.get("domain") or cfg_map.get("notifyDomain")
48
47
  domain = domain or os.getenv("MAILGUN_DOMAIN") or os.getenv("MAILGUN_NOTIFY_DOMAIN")
49
48
  if not domain:
@@ -96,11 +95,15 @@ async def send_email_with_mailgun(
96
95
  # Try to return JSON payload if available
97
96
  try:
98
97
  return await response.json()
99
- except Exception:
98
+ except Exception as parse_ex:
99
+ logging.debug(f"Could not parse Mailgun response as JSON: {parse_ex}")
100
100
  return await response.text()
101
- except Exception as ex:
101
+ except (aiohttp.ClientError, ValueError) as ex:
102
102
  logging.warning(f"Error sending email via Mailgun: {ex}")
103
103
  return {"error": str(ex)}
104
+ except Exception as ex:
105
+ logging.exception(f"Unexpected error sending email via Mailgun: {ex}")
106
+ raise
104
107
 
105
108
 
106
109
  async def send_email_using_mailgun_async(
@@ -147,10 +150,10 @@ async def send_email_using_mailgun_async(
147
150
  raise RuntimeError(f"Mailgun send failed: {detail}")
148
151
  try:
149
152
  payload = await response.json()
150
- except Exception:
153
+ except Exception as parse_ex:
154
+ logging.debug(f"Could not parse Mailgun response as JSON: {parse_ex}")
151
155
  payload = {"message": await response.text()}
152
156
 
153
157
  # Normalise return value akin to other providers
154
158
  msg_id = payload.get("id") if isinstance(payload, dict) else None
155
- await asyncio.sleep(20)
156
159
  return msg_id or str(payload)
@@ -119,13 +119,17 @@ async def send_email_with_sendgrid(
119
119
  headers=headers,
120
120
  json=payload,
121
121
  ) as response:
122
- # SendGrid returns 202 Accepted on success with empty body
122
+ # SendGrid returns 202 Accepted on success with empty body but includes X-Message-Id header
123
123
  if response.status == 202:
124
- return {"status": 202, "message": "accepted"}
124
+ message_id = response.headers.get("X-Message-Id")
125
+ if not message_id:
126
+ logging.warning("SendGrid did not return X-Message-Id header")
127
+ return {"status": 202, "message": "accepted", "message_id": message_id}
125
128
  # On error, try to parse JSON for helpful message
126
129
  try:
127
130
  err = await response.json()
128
- except Exception:
131
+ except Exception as parse_ex:
132
+ logging.debug(f"Could not parse SendGrid error as JSON: {parse_ex}")
129
133
  err = {"text": await response.text()}
130
134
  return {"error": err, "status": response.status}
131
135
  except Exception as ex:
@@ -139,12 +143,8 @@ async def send_email_using_sendgrid_async(
139
143
  ) -> str:
140
144
  """
141
145
  Provider-style wrapper for SendGrid using SendEmailContext.
142
- Returns an opaque token since SendGrid does not return a message id.
146
+ Returns the message ID from SendGrid's X-Message-Id response header.
143
147
  """
144
- plain_body, html_body, _ = body_variants(
145
- ctx.body,
146
- getattr(ctx, "body_format", None),
147
- )
148
148
  result = await send_email_with_sendgrid(
149
149
  sender=f"{ctx.sender_name} <{ctx.sender_email}>",
150
150
  recipients=[ctx.recipient],
@@ -156,6 +156,10 @@ async def send_email_using_sendgrid_async(
156
156
  )
157
157
  # Normalise output to a string id-like value
158
158
  if isinstance(result, dict) and result.get("status") == 202:
159
+ message_id = result.get("message_id")
160
+ if message_id:
161
+ return message_id
162
+ # Fallback if header wasn't present (shouldn't happen)
159
163
  return f"sent:{ctx.sender_email}:{ctx.recipient}:{ctx.subject}"
160
164
  if isinstance(result, dict) and "error" in result:
161
165
  raise RuntimeError(f"SendGrid send failed: {result['error']}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev265
3
+ Version: 0.0.1.dev266
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
@@ -31,7 +31,7 @@ dhisana/utils/dataframe_tools.py,sha256=R6eUXjwR5SG6_K87rWjj4T5PT2w6xvVF2EKBajIv
31
31
  dhisana/utils/domain_parser.py,sha256=Kw5MPP06wK2azWQzuSiOE-DffOezLqDyF-L9JEBsMSU,1206
32
32
  dhisana/utils/email_body_utils.py,sha256=rlCVjdBlqNnEiUberJGXGcrYY1GQOkW0-aB6AEpS3L4,2302
33
33
  dhisana/utils/email_parse_helpers.py,sha256=LIdm1B1IyGSW50y8EkxOk6YRjvxO2SJTgTKPLxYls_o,4613
34
- dhisana/utils/email_provider.py,sha256=spjbNdnaVfCZEUw62EEHKijuXjI7vTVNqsftxJ15Erw,14352
34
+ dhisana/utils/email_provider.py,sha256=ukW_0nHcjTQmpnE9pdJci78LrZcsK1_0v6kcgc2ChPY,14573
35
35
  dhisana/utils/enrich_lead_information.py,sha256=O0fV-8MlXFT_z5aXvmvXVT76AISN94GpvAOlq3q_Phw,39411
36
36
  dhisana/utils/extract_email_content_for_llm.py,sha256=SQmMZ3YJtm3ZI44XiWEVAItcAwrsSSy1QzDne7LTu_Q,3713
37
37
  dhisana/utils/fetch_openai_config.py,sha256=LjWdFuUeTNeAW106pb7DLXZNElos2PlmXRe6bHZJ2hw,5159
@@ -54,7 +54,7 @@ dhisana/utils/hubspot_crm_tools.py,sha256=lbXFCeq690_TDLjDG8Gm5E-2f1P5EuDqNf5j8P
54
54
  dhisana/utils/instantly_tools.py,sha256=hhqjDPyLE6o0dzzuvryszbK3ipnoGU2eBm6NlsUGJjY,4771
55
55
  dhisana/utils/linkedin_crawler.py,sha256=6fMQTY5lTw2kc65SFHgOAM6YfezAS0Yhg-jkiX8LGHo,6533
56
56
  dhisana/utils/lusha_tools.py,sha256=MdiWlxBBjSNpSKz8rhNOyLPtbeh-YWHgGiUq54vN_gM,12734
57
- dhisana/utils/mailgun_tools.py,sha256=OTesN8spYrvoH4Q5BheC8TPUvUlfbZhliYOhzCrD7Mg,5506
57
+ dhisana/utils/mailgun_tools.py,sha256=brOgfEx-ciqEdDkXEfzMBfXkG0kRWVscg76tQDXb_lk,5826
58
58
  dhisana/utils/mailreach_tools.py,sha256=uJ_gIcg8qrj5-k3jnYYhpwLVnQncoA1swzr5Jfkc1JU,3864
59
59
  dhisana/utils/microsoft365_tools.py,sha256=ClqBzTrJ2SZM5K9nsOFyyHRfV-d-6jlxXNpNONtgLlY,18596
60
60
  dhisana/utils/openai_assistant_and_file_utils.py,sha256=-eyPcxFvtS-DDtYQGle1SU6C6CuxjulVIojFy27HeWc,8957
@@ -70,7 +70,7 @@ dhisana/utils/sales_navigator_crawler.py,sha256=z8yurwUTLXdM71xWPDSAFNuDyA_SlanT
70
70
  dhisana/utils/salesforce_crm_tools.py,sha256=r6tROej4PtfcRN2AViPD7tV24oxBNm6QCE7uwhDH5Hc,17169
71
71
  dhisana/utils/search_router.py,sha256=p_1MPHbjalBM8gZuU4LADbmqSLNtZ4zll6CbPOc0POU,4610
72
72
  dhisana/utils/search_router_jobs.py,sha256=LgCHNGLMSv-ovgzF32muprfaDTdTpIKgrP5F7swAqhk,1721
73
- dhisana/utils/sendgrid_tools.py,sha256=VyiLbQfa0xYY-onWqhHRcNKL7z-Wev-t4lim1d-vDVw,5526
73
+ dhisana/utils/sendgrid_tools.py,sha256=0aafzCxcmCtKVt7kWYNTH_Np9KF0-RPqAZ9LsslMlqs,5931
74
74
  dhisana/utils/serarch_router_local_business.py,sha256=n9yZjeXKOSgBnr0lCSQomP1nN3ucbC9ZTTSmSHQLeVo,2920
75
75
  dhisana/utils/serpapi_additional_tools.py,sha256=Xb1tc_oK-IjI9ZrEruYhFg8UJMLHQDaO9B51YiNbeBs,10569
76
76
  dhisana/utils/serpapi_google_jobs.py,sha256=HUJFZEW8UvYqsW0sWlEDXgI_IUomh5fTkzRJzEgsDGc,4509
@@ -95,8 +95,8 @@ dhisana/workflow/agent.py,sha256=esv7_i_XuMkV2j1nz_UlsHov_m6X5WZZiZm_tG4OBHU,565
95
95
  dhisana/workflow/flow.py,sha256=xWE3qQbM7j2B3FH8XnY3zOL_QXX4LbTW4ArndnEYJE0,1638
96
96
  dhisana/workflow/task.py,sha256=HlWz9mtrwLYByoSnePOemBUBrMEcj7KbgNjEE1oF5wo,1830
97
97
  dhisana/workflow/test.py,sha256=E7lRnXK0PguTNzyasHytLzTJdkqIPxG5_4qk4hMEeKc,3399
98
- dhisana-0.0.1.dev265.dist-info/METADATA,sha256=S6o7HBV1UGxYP3ltCxcwGEYDhpQ5VsZ_sEUXvf_cIcY,1190
99
- dhisana-0.0.1.dev265.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
100
- dhisana-0.0.1.dev265.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
101
- dhisana-0.0.1.dev265.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
102
- dhisana-0.0.1.dev265.dist-info/RECORD,,
98
+ dhisana-0.0.1.dev266.dist-info/METADATA,sha256=KEVAlP8-K5O412xaBb3WeJWM6S1thO8dRYiEu3PQKvw,1190
99
+ dhisana-0.0.1.dev266.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
100
+ dhisana-0.0.1.dev266.dist-info/entry_points.txt,sha256=jujxteZmNI9EkEaK-pOCoWuBujU8TCevdkfl9ZcKHek,49
101
+ dhisana-0.0.1.dev266.dist-info/top_level.txt,sha256=NETTHt6YifG_P7XtRHbQiXZlgSFk9Qh9aR-ng1XTf4s,8
102
+ dhisana-0.0.1.dev266.dist-info/RECORD,,