dgsender 1.0.0a2__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [year] [fullname]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,670 @@
1
+ Metadata-Version: 2.4
2
+ Name: dgsender
3
+ Version: 1.0.0a2
4
+ Summary: Unified sender package for email, telegram, slack and zabbix with async support.
5
+ Author-email: Roman Rasputin <admin@roro.su>
6
+ License: MIT License
7
+ Project-URL: Homepage, https://gitlab.com/gng-group/dgsender
8
+ Project-URL: BugTracker, https://gitlab.com/gng-group/dgsender/issues
9
+ Keywords: telegram,email,zabbix
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: System :: Distributed Computing
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: requests>=2.25.0
24
+ Provides-Extra: mail
25
+ Provides-Extra: tg
26
+ Requires-Dist: requests>=2.25.0; extra == "tg"
27
+ Provides-Extra: zabbix
28
+ Requires-Dist: divinegift>=1.3.16; extra == "zabbix"
29
+ Provides-Extra: slack
30
+ Requires-Dist: requests>=2.25.0; extra == "slack"
31
+ Provides-Extra: async-mail
32
+ Provides-Extra: async-tg
33
+ Requires-Dist: aiohttp>=3.8.0; extra == "async-tg"
34
+ Provides-Extra: async-slack
35
+ Requires-Dist: aiohttp>=3.8.0; extra == "async-slack"
36
+ Provides-Extra: metrics
37
+ Requires-Dist: dgmetrics>=1.0.0a7; extra == "metrics"
38
+ Provides-Extra: all
39
+ Requires-Dist: requests>=2.25.0; extra == "all"
40
+ Requires-Dist: aiohttp>=3.8.0; extra == "all"
41
+ Requires-Dist: dgmetrics>=1.0.0a7; extra == "all"
42
+ Dynamic: license-file
43
+
44
+ ```markdown
45
+ # dgsender
46
+
47
+ Unified sender package for email, telegram, slack and zabbix with async support.
48
+
49
+ ## Features
50
+
51
+ - πŸ“§ **Email sending** - SMTP with TLS/SSL support, attachments, HTML emails
52
+ - πŸ“± **Telegram** - Bot messaging with proxy support
53
+ - πŸ’¬ **Slack/Mattermost** - Webhook integration
54
+ - πŸ“Š **Zabbix** - Monitoring data submission
55
+ - ⚑ **Async support** - Non-blocking operations for high performance
56
+ - πŸ“ˆ **Metrics integration** - Optional metrics collection with dgmetrics
57
+ - πŸͺ΅ **Custom logging** - Flexible logging configuration
58
+ - πŸ”§ **Modular design** - Install only what you need
59
+
60
+ ## Installation
61
+
62
+ ### Basic installation
63
+ ```bash
64
+ pip install dgsender
65
+ ```
66
+
67
+ ### With specific features
68
+ ```bash
69
+ # Telegram only
70
+ pip install dgsender[tg]
71
+
72
+ # Email only
73
+ pip install dgsender[mail]
74
+
75
+ # Zabbix only
76
+ pip install dgsender[zabbix]
77
+
78
+ # Async support
79
+ pip install dgsender[async]
80
+
81
+ # Metrics support
82
+ pip install dgsender[metrics]
83
+
84
+ # All features
85
+ pip install dgsender[all]
86
+ ```
87
+
88
+ ## Quick Start
89
+
90
+ ### Email Sending
91
+
92
+ ```python
93
+ from dgsender import EmailSender
94
+
95
+ # Synchronous email sender
96
+ email_sender = EmailSender(
97
+ host="smtp.gmail.com",
98
+ port=587,
99
+ use_tls=True,
100
+ username="user@gmail.com",
101
+ password="password"
102
+ )
103
+
104
+ email_sender.send(
105
+ msg="Hello from dgsender!",
106
+ subject="Test Email",
107
+ to=["recipient@example.com"],
108
+ from_addr="sender@example.com",
109
+ is_html=True
110
+ )
111
+ ```
112
+
113
+ ### Telegram Messages
114
+
115
+ ```python
116
+ from dgsender import TelegramSender
117
+
118
+ tg_sender = TelegramSender(token="your_bot_token")
119
+ tg_sender.send("Hello Telegram!", chat_id=123456789)
120
+ ```
121
+
122
+ ## Async Senders
123
+
124
+ ### Async Email Sender
125
+ ```python
126
+ import asyncio
127
+ from dgsender import AsyncEmailSender
128
+
129
+ async def main():
130
+ sender = AsyncEmailSender(
131
+ host="smtp.gmail.com",
132
+ port=587,
133
+ use_tls=True,
134
+ username="user@gmail.com",
135
+ password="password"
136
+ )
137
+
138
+ # Send single email
139
+ await sender.send(
140
+ msg="Hello from async!",
141
+ subject="Async Test",
142
+ to=["user@example.com"]
143
+ )
144
+
145
+ # Send multiple emails concurrently
146
+ messages = [
147
+ {
148
+ "msg": "Message 1",
149
+ "subject": "Test 1",
150
+ "to": ["user1@example.com"]
151
+ },
152
+ {
153
+ "msg": "Message 2",
154
+ "subject": "Test 2",
155
+ "to": ["user2@example.com"]
156
+ }
157
+ ]
158
+ results = await sender.send_multiple(messages)
159
+
160
+ asyncio.run(main())
161
+ ```
162
+
163
+ ## Core Components
164
+
165
+ ### Email Senders
166
+
167
+ #### Synchronous EmailSender
168
+ ```python
169
+ from dgsender import EmailSender
170
+
171
+ sender = EmailSender(
172
+ host="smtp.example.com",
173
+ port=587,
174
+ use_tls=True,
175
+ username="user@example.com",
176
+ password="password"
177
+ )
178
+
179
+ # Send with attachments
180
+ sender.send(
181
+ msg="<h1>HTML Content</h1>",
182
+ subject="Email with attachments",
183
+ to=["user1@example.com", "user2@example.com"],
184
+ cc=["manager@example.com"],
185
+ attachments=["file1.pdf", "image.jpg"],
186
+ is_html=True
187
+ )
188
+ ```
189
+
190
+ #### Asynchronous AsyncEmailSender
191
+ ```python
192
+ from dgsender import AsyncEmailSender
193
+
194
+ async def send_emails():
195
+ sender = AsyncEmailSender(
196
+ host="smtp.example.com",
197
+ port=587,
198
+ use_tls=True
199
+ )
200
+
201
+ await sender.send(
202
+ msg="Async email content",
203
+ subject="Async Test",
204
+ to=["user@example.com"]
205
+ )
206
+ ```
207
+
208
+ ### Telegram Senders
209
+
210
+ #### Synchronous TelegramSender
211
+ ```python
212
+ from dgsender import TelegramSender
213
+
214
+ # Basic usage
215
+ tg = TelegramSender(token="your_bot_token")
216
+ tg.send("Simple message", chat_id=123456)
217
+
218
+ # With proxy and custom options
219
+ tg = TelegramSender(
220
+ token="your_bot_token",
221
+ base_url="https://api.telegram.org/bot",
222
+ proxy={"http": "http://proxy:3128", "https": "https://proxy:3128"}
223
+ )
224
+
225
+ tg.send(
226
+ "Formatted message",
227
+ chat_id=123456,
228
+ parse_mode="Markdown",
229
+ disable_web_page_preview=True
230
+ )
231
+ ```
232
+
233
+ #### Asynchronous AsyncTelegramSender
234
+ ```python
235
+ from dgsender import AsyncTelegramSender
236
+
237
+ async def send_telegram():
238
+ tg = AsyncTelegramSender(token="your_bot_token")
239
+ await tg.send("Async telegram message", chat_id=123456)
240
+ ```
241
+
242
+ ### Slack/Mattermost Senders
243
+
244
+ ```python
245
+ from dgsender import SlackSender
246
+
247
+ slack = SlackSender(webhook_url="https://hooks.slack.com/services/XXX")
248
+ slack.send("Hello Slack!")
249
+
250
+ # With custom options
251
+ slack.send(
252
+ "Custom message",
253
+ channel="#alerts",
254
+ username="MyBot",
255
+ icon_url="https://example.com/icon.png"
256
+ )
257
+ ```
258
+
259
+ ### Zabbix Sender
260
+
261
+ ```python
262
+ from dgsender import ZabbixSender
263
+
264
+ zabbix = ZabbixSender(server="zabbix.example.com", port=10051)
265
+ zabbix.send(
266
+ host="web-server-01",
267
+ key="web.response.time",
268
+ value=150
269
+ )
270
+ ```
271
+
272
+ ### Composite Sender
273
+
274
+ ```python
275
+ from dgsender import CompositeSender, TelegramSender, EmailSender, SlackSender
276
+
277
+ # Create multiple senders
278
+ tg_sender = TelegramSender(token="tg_token")
279
+ email_sender = EmailSender(host="smtp.example.com")
280
+ slack_sender = SlackSender(webhook_url="slack_webhook")
281
+
282
+ # Combine them
283
+ composite = CompositeSender(senders=[tg_sender, email_sender, slack_sender])
284
+
285
+ # Send to all channels
286
+ results = composite.send_all(
287
+ "Important notification!",
288
+ # Telegram specific
289
+ chat_id=123456,
290
+ # Email specific
291
+ subject="Alert",
292
+ to=["admin@example.com"],
293
+ # Slack specific
294
+ channel="#alerts"
295
+ )
296
+
297
+ print(f"Results: {results}")
298
+ ```
299
+
300
+ ## Advanced Usage
301
+
302
+ ### Custom Logging
303
+
304
+ ```python
305
+ import logging
306
+ from dgsender import EmailSender
307
+
308
+ # Setup custom logger
309
+ logger = logging.getLogger('my_app')
310
+ handler = logging.StreamHandler()
311
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
312
+ handler.setFormatter(formatter)
313
+ logger.addHandler(handler)
314
+
315
+ # Use custom logger
316
+ sender = EmailSender(
317
+ host="smtp.example.com",
318
+ logger_instance=logger
319
+ )
320
+ ```
321
+
322
+ ### Metrics Integration
323
+
324
+ ```python
325
+ from dgsender import EmailSender, TelegramSender
326
+ from dgmetrics import Metrics # Optional dependency
327
+
328
+ # Initialize metrics
329
+ metrics = Metrics()
330
+
331
+ # Senders with metrics
332
+ email_sender = EmailSender(
333
+ host="smtp.example.com",
334
+ metrics_instance=metrics
335
+ )
336
+
337
+ tg_sender = TelegramSender(
338
+ token="your_bot_token",
339
+ metrics_instance=metrics
340
+ )
341
+
342
+ # Send messages (metrics are collected automatically)
343
+ email_sender.send(...)
344
+ tg_sender.send(...)
345
+ ```
346
+
347
+ ### Custom Metrics Class
348
+
349
+ ```python
350
+ from dgsender import EmailSender
351
+
352
+ class MyMetrics:
353
+ def counter(self, name, value=1, tags=None):
354
+ print(f"Counter: {name} = {value}")
355
+
356
+ def gauge(self, name, value, tags=None):
357
+ print(f"Gauge: {name} = {value}")
358
+
359
+ def timer(self, name, value, tags=None):
360
+ print(f"Timer: {name} = {value}s")
361
+
362
+ sender = EmailSender(
363
+ host="smtp.example.com",
364
+ metrics_instance=MyMetrics()
365
+ )
366
+ ```
367
+
368
+ ### Error Handling
369
+
370
+ ```python
371
+ from dgsender import EmailSender, EmailSendError
372
+
373
+ sender = EmailSender(host="smtp.example.com")
374
+
375
+ try:
376
+ sender.send(
377
+ msg="Test message",
378
+ subject="Test",
379
+ to=["user@example.com"]
380
+ )
381
+ except EmailSendError as e:
382
+ print(f"Failed to send email: {e}")
383
+ except Exception as e:
384
+ print(f"Unexpected error: {e}")
385
+ ```
386
+
387
+ ### Low-level Mailer Usage
388
+
389
+ ```python
390
+ from dgsender import Mailer, AsyncMailer, Message
391
+
392
+ # Synchronous mailer
393
+ mailer = Mailer(host="smtp.example.com", port=587)
394
+ message = Message(
395
+ From="sender@example.com",
396
+ To="recipient@example.com",
397
+ Subject="Direct Message",
398
+ Body="Hello from low-level mailer!"
399
+ )
400
+ mailer.send(message)
401
+
402
+ # Asynchronous mailer
403
+ async def async_send():
404
+ mailer = AsyncMailer(host="smtp.example.com", port=587)
405
+ await mailer.send(message)
406
+ ```
407
+
408
+ ## Configuration
409
+
410
+ ### Email Configuration
411
+
412
+ | Parameter | Type | Default | Description |
413
+ |-----------|------|---------|-------------|
414
+ | `host` | str | "localhost" | SMTP server host |
415
+ | `port` | int | 0 | SMTP server port |
416
+ | `use_tls` | bool | False | Enable TLS encryption |
417
+ | `use_ssl` | bool | False | Enable SSL encryption |
418
+ | `username` | str | None | SMTP username |
419
+ | `password` | str | None | SMTP password |
420
+ | `reopen_mail_session` | bool | True | Recreate connection for each send |
421
+
422
+ ### Telegram Configuration
423
+
424
+ | Parameter | Type | Default | Description |
425
+ |-----------|------|---------|-------------|
426
+ | `token` | str | Required | Bot token from BotFather |
427
+ | `base_url` | str | "https://api.telegram.org/bot" | Telegram API base URL |
428
+ | `proxy` | dict | None | Proxy configuration |
429
+
430
+ ### Common Parameters
431
+
432
+ All senders support:
433
+ - `logger_instance`: Custom logger instance
434
+ - `metrics_instance`: Metrics collector instance
435
+
436
+ ## Exception Types
437
+
438
+ | Exception | Description |
439
+ |-----------|-------------|
440
+ | `DGSenderError` | Base exception for all sender errors |
441
+ | `EmailSendError` | Email sending related errors |
442
+ | `TelegramSendError` | Telegram sending related errors |
443
+ | `SlackSendError` | Slack/Mattermost sending related errors |
444
+ | `ZabbixSendError` | Zabbix data submission errors |
445
+
446
+ ## SSL/TLS Configuration
447
+
448
+ ### SSL for Requests-based Senders (Telegram, Slack)
449
+
450
+ ```python
451
+ from dgsender import TelegramSender, SlackSender
452
+
453
+ # Disable SSL verification (not recommended for production)
454
+ tg_sender = TelegramSender(
455
+ token="your_bot_token",
456
+ verify_ssl=False # Disable certificate verification
457
+ )
458
+
459
+ # Use client certificate
460
+ tg_sender = TelegramSender(
461
+ token="your_bot_token",
462
+ ssl_cert=("/path/to/client.crt", "/path/to/client.key") # Client certificate
463
+ )
464
+
465
+ # For Slack
466
+ slack_sender = SlackSender(
467
+ webhook_url="your_webhook",
468
+ verify_ssl=False # Disable verification
469
+ )
470
+ ```
471
+
472
+ ### SSL for Async Senders (aiohttp-based)
473
+
474
+ ```python
475
+ import ssl
476
+ from dgsender import AsyncTelegramSender, AsyncSlackSender
477
+
478
+ # Disable SSL verification
479
+ async_tg_sender = AsyncTelegramSender(
480
+ token="your_bot_token",
481
+ verify_ssl=False
482
+ )
483
+
484
+ # Use custom SSL context
485
+ ssl_context = ssl.create_default_context()
486
+ ssl_context.load_verify_locations(cafile="/path/to/ca-bundle.crt")
487
+
488
+ async_tg_sender = AsyncTelegramSender(
489
+ token="your_bot_token",
490
+ ssl_context=ssl_context
491
+ )
492
+
493
+ # Use client certificate
494
+ async_tg_sender = AsyncTelegramSender(
495
+ token="your_bot_token",
496
+ client_cert="/path/to/client.crt",
497
+ client_key="/path/to/client.key"
498
+ )
499
+
500
+ # For Slack
501
+ async_slack_sender = AsyncSlackSender(
502
+ webhook_url="your_webhook",
503
+ verify_ssl=True,
504
+ client_cert="/path/to/client.crt",
505
+ client_key="/path/to/client.key"
506
+ )
507
+ ```
508
+
509
+ ### Advanced SSL Configuration
510
+
511
+ ```python
512
+ import ssl
513
+ from dgsender import AsyncTelegramSender
514
+
515
+ # Create custom SSL context with specific settings
516
+ ssl_context = ssl.create_default_context()
517
+ ssl_context.check_hostname = True
518
+ ssl_context.verify_mode = ssl.CERT_REQUIRED
519
+ ssl_context.load_default_certs()
520
+ ssl_context.load_verify_locations(cafile="/path/to/custom-ca-bundle.crt")
521
+
522
+ sender = AsyncTelegramSender(
523
+ token="your_bot_token",
524
+ ssl_context=ssl_context
525
+ )
526
+ ```
527
+
528
+ ## SSL Configuration Parameters
529
+
530
+ ### For Requests-based Senders:
531
+ - `verify_ssl`: bool - Enable/disable SSL certificate verification (default: True)
532
+ - `ssl_cert`: str or tuple - Path to client certificate file, or tuple (cert, key)
533
+
534
+ ### For Async Senders (aiohttp):
535
+ - `verify_ssl`: bool - Enable/disable SSL certificate verification (default: True)
536
+ - `ssl_context`: ssl.SSLContext - Custom SSL context
537
+ - `client_cert`: str - Path to client certificate file
538
+ - `client_key`: str - Path to client private key file
539
+ ```
540
+
541
+ ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования SSL:
542
+
543
+ ### Π‘Π°Π·ΠΎΠ²ΠΎΠ΅ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ SSL:
544
+ ```python
545
+ from dgsender import TelegramSender
546
+
547
+ # Для тСстовых срСд ΠΈΠ»ΠΈ самоподписанных сСртификатов
548
+ tg = TelegramSender(
549
+ token="your_bot_token",
550
+ verify_ssl=False
551
+ )
552
+ ```
553
+
554
+ ### ИспользованиС клиСнтского сСртификата:
555
+ ```python
556
+ from dgsender import TelegramSender
557
+
558
+ # Для сСрвСров, Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‰ΠΈΡ… ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΡΠΊΡƒΡŽ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡŽ
559
+ tg = TelegramSender(
560
+ token="your_bot_token",
561
+ ssl_cert=("/path/to/client.crt", "/path/to/client.key")
562
+ )
563
+ ```
564
+
565
+ ### ΠŸΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚Π°Ρ SSL конфигурация для async:
566
+ ```python
567
+ import ssl
568
+ from dgsender import AsyncTelegramSender
569
+
570
+ # Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ кастомного SSL контСкста
571
+ context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
572
+ context.load_cert_chain(
573
+ certfile="/path/to/client.crt",
574
+ keyfile="/path/to/client.key"
575
+ )
576
+ context.load_verify_locations(cafile="/path/to/ca-bundle.crt")
577
+
578
+ sender = AsyncTelegramSender(
579
+ token="your_bot_token",
580
+ ssl_context=context
581
+ )
582
+ ```
583
+
584
+
585
+ ## Performance Tips
586
+
587
+ ### Use Async Senders for High Throughput
588
+
589
+ ```python
590
+ import asyncio
591
+ from dgsender import AsyncEmailSender
592
+
593
+ async def send_bulk_emails(messages):
594
+ sender = AsyncEmailSender(host="smtp.example.com")
595
+ tasks = []
596
+
597
+ for msg_data in messages:
598
+ task = sender.send(**msg_data)
599
+ tasks.append(task)
600
+
601
+ # Send all emails concurrently
602
+ await asyncio.gather(*tasks, return_exceptions=True)
603
+ ```
604
+
605
+ ### Reuse Sender Instances
606
+
607
+ ```python
608
+ # Good: Reuse sender instance
609
+ sender = EmailSender(host="smtp.example.com")
610
+ for message in messages:
611
+ sender.send(**message)
612
+
613
+ # Avoid: Creating new sender for each message
614
+ for message in messages:
615
+ sender = EmailSender(host="smtp.example.com") # Inefficient
616
+ sender.send(**message)
617
+ ```
618
+
619
+ ## Testing
620
+
621
+ ```python
622
+ from dgsender import EmailSender
623
+ import unittest
624
+ from unittest.mock import Mock
625
+
626
+ class TestEmailSender(unittest.TestCase):
627
+ def setUp(self):
628
+ self.sender = EmailSender(host="localhost", port=1025) # Test SMTP
629
+
630
+ def test_send_email(self):
631
+ # Test email sending logic
632
+ result = self.sender.send(
633
+ msg="Test message",
634
+ subject="Test",
635
+ to=["test@example.com"]
636
+ )
637
+ # Add your assertions here
638
+
639
+ if __name__ == "__main__":
640
+ unittest.main()
641
+ ```
642
+
643
+ ## Contributing
644
+
645
+ 1. Fork the repository
646
+ 2. Create a feature branch
647
+ 3. Make your changes
648
+ 4. Add tests
649
+ 5. Submit a pull request
650
+
651
+ ## License
652
+
653
+ MIT License - see LICENSE file for details.
654
+
655
+ ## Support
656
+
657
+ For issues and questions:
658
+ - Create an issue on GitHub
659
+ - Check existing documentation
660
+ - Review example code in the repository
661
+
662
+ ## Changelog
663
+
664
+ ### v1.0.0
665
+ - Initial release
666
+ - Email, Telegram, Slack, Zabbix senders
667
+ - Async support
668
+ - Metrics integration
669
+ - Custom logging support
670
+ ```