Skip to content

Commit 1b8d0c3

Browse files
Merge pull request #126 from mymah01/feature/batchmail-return-json
Return full Postmark API response from send() and add tests
2 parents 6c4ee0b + bda9fe2 commit 1b8d0c3

File tree

2 files changed

+112
-4
lines changed

2 files changed

+112
-4
lines changed

postmark/core.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ def to_json_message(self):
504504

505505
return json_message
506506

507-
def send(self, test=None):
507+
def send(self, test=None, return_json=None):
508508
'''
509509
Send the email through the Postmark system.
510510
Pass test=True to just print out the resulting
@@ -537,6 +537,21 @@ def send(self, test=None):
537537
else:
538538
endpoint_url = __POSTMARK_URL__ + 'email'
539539

540+
"""
541+
Args:
542+
return_json (bool | None):
543+
True -> return parsed JSON
544+
False -> return True/False
545+
None -> fallback to settings.POSTMARK_RETURN_JSON (default False)
546+
"""
547+
548+
if return_json is None:
549+
try:
550+
from django.conf import settings as django_settings
551+
return_json = getattr(django_settings, "POSTMARK_RETURN_JSON", False)
552+
except ImportError:
553+
return_json = False
554+
540555
# Set up the url Request
541556
req = Request(
542557
endpoint_url,
@@ -556,8 +571,9 @@ def send(self, test=None):
556571
jsontxt = result.read().decode('utf8')
557572
result.close()
558573
if result.code == 200:
559-
self.message_id = json.loads(jsontxt).get('MessageID', None)
560-
return True
574+
parsed = json.loads(jsontxt)
575+
self.message_id = parsed.get("MessageID", None)
576+
return parsed if return_json else True
561577
else:
562578
raise PMMailSendException('Return code %d: %s' % (result.code, result.msg))
563579
except HTTPError as err:
@@ -676,7 +692,7 @@ def _check_values(self):
676692

677693
message._check_values()
678694

679-
def send(self, test=None):
695+
def send(self, test=None, return_json=None):
680696
# Has one of the messages caused an inactive recipient error?
681697
inactive_recipient = False
682698

@@ -691,6 +707,21 @@ def send(self, test=None):
691707
except ImportError:
692708
pass
693709

710+
"""
711+
Args:
712+
return_json (bool | None):
713+
True -> return parsed JSON
714+
False -> return True/False
715+
None -> fallback to settings.POSTMARK_RETURN_JSON (default False)
716+
"""
717+
718+
if return_json is None:
719+
try:
720+
from django.conf import settings as django_settings
721+
return_json = getattr(django_settings, "POSTMARK_RETURN_JSON", False)
722+
except ImportError:
723+
return_json = False
724+
694725
# Split up into groups of 500 messages for sending
695726
for messages in _chunks(self.messages, PMBatchMail.MAX_MESSAGES):
696727
json_message = []
@@ -729,6 +760,7 @@ def send(self, test=None):
729760
results = json.loads(jsontxt)
730761
for i, res in enumerate(results):
731762
self.__messages[i].message_id = res.get("MessageID", None)
763+
return results if return_json else True
732764
else:
733765
raise PMMailSendException('Return code %d: %s' % (result.code, result.msg))
734766
except HTTPError as err:

tests.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import mock
2222

23+
from unittest.mock import MagicMock
24+
2325
from postmark import (
2426
PMBatchMail, PMMail, PMMailInactiveRecipientException,
2527
PMMailUnprocessableEntityException, PMMailServerErrorException,
@@ -29,6 +31,15 @@
2931
from django.conf import settings
3032

3133

34+
def make_fake_response(payload, code=200):
35+
"""Helper to fake an HTTP response object."""
36+
mock = MagicMock()
37+
mock.code = code
38+
mock.read.return_value = json.dumps(payload).encode("utf-8")
39+
mock.close.return_value = None
40+
return mock
41+
42+
3243
class PMMailTests(unittest.TestCase):
3344
def test_406_error_inactive_recipient(self):
3445
json_payload = BytesIO()
@@ -181,6 +192,37 @@ def test_send_metadata_invalid_format(self):
181192
self.assertRaises(TypeError, PMMail, api_key='test', sender='from@example.com', to='to@example.com',
182193
subject='test', text_body='test', metadata={'test': {}})
183194

195+
def test_mail_returns_result(self):
196+
fake_payload = {
197+
"To": "receiver@example.com",
198+
"SubmittedAt": "2025-09-18T10:00:00Z",
199+
"MessageID": "abc-123",
200+
"ErrorCode": 0,
201+
"Message": "OK"
202+
}
203+
204+
mail = PMMail(
205+
api_key="test-api-key",
206+
sender="sender@example.com",
207+
to="receiver@example.com",
208+
subject="Hello",
209+
text_body="Testing single mail return",
210+
)
211+
212+
with mock.patch("postmark.core.urlopen") as mock_urlopen:
213+
mock_urlopen.return_value = make_fake_response(fake_payload)
214+
215+
# Test boolean return
216+
result = mail.send()
217+
self.assertTrue(result)
218+
219+
# Test JSON return explicitly
220+
result_json = mail.send(return_json=True)
221+
self.assertIsInstance(result_json, dict)
222+
self.assertEqual(result_json["ErrorCode"], 0)
223+
self.assertEqual(result_json["Message"], "OK")
224+
225+
184226

185227
class PMBatchMailTests(unittest.TestCase):
186228
def test_406_error_inactive_recipient(self):
@@ -245,6 +287,40 @@ def test_500_error_server_error(self):
245287
500, '', {}, None)):
246288
self.assertRaises(PMMailServerErrorException, batch.send)
247289

290+
def test_batch_mail_returns_results(self):
291+
fake_payload = [
292+
{
293+
"To": "receiver@example.com",
294+
"SubmittedAt": "2025-09-18T10:00:00Z",
295+
"MessageID": "abc-123",
296+
"ErrorCode": 0,
297+
"Message": "OK",
298+
}
299+
]
300+
301+
message = PMMail(
302+
api_key="test-api-key",
303+
sender="sender@example.com",
304+
to="receiver@example.com",
305+
subject="Hello",
306+
text_body="Testing batch return",
307+
)
308+
# pass list of PMMail objects to PMBatchMail
309+
batch = PMBatchMail(api_key="test-api-key", messages=[message])
310+
311+
with mock.patch("postmark.core.urlopen") as mock_urlopen:
312+
mock_urlopen.return_value = make_fake_response(fake_payload)
313+
314+
# Test boolean return
315+
results = batch.send()
316+
self.assertTrue(results)
317+
318+
# Test JSON return explicitly
319+
results_json = batch.send(return_json=True)
320+
self.assertIsInstance(results_json, list)
321+
self.assertEqual(results_json[0]["ErrorCode"], 0)
322+
323+
248324

249325
class PMBounceManagerTests(unittest.TestCase):
250326
def test_activate(self):

0 commit comments

Comments
 (0)