diff --git a/PySMS.py b/PySMS.py index cac4345..0bbc4a3 100644 --- a/PySMS.py +++ b/PySMS.py @@ -9,6 +9,7 @@ import inspect import logging import threading +import constants class PySMSException: @@ -22,31 +23,6 @@ def __str__(self): class PySMS: def __init__(self, address, password, smtp_server, smtp_port, imap_server=None, ssl=False, window=5, delimiter=":", identifier_length=4, max_tries=5, text_wait_time=5, check_wait_time=15, check_unit=60, debug=False): - self.carriers = { - # US - "alltel": "@mms.alltelwireless.com", - "att": "@mms.att.net", - "boost": "@myboostmobile.com", - "cricket": "@mms.cricketwireless.net", - "p_fi": "msg.fi.google.com", - "sprint": "@pm.sprint.com", - "tmobile": "@tmomail.net", - "us_cellular": "@mms.uscc.net", - "verizon": "@vzwpix.com", - "virgin": "@vmpix.com", - # Canada - "bell": "@txt.bell.ca", - "chatr": "@fido.ca", - "fido": "@fido.ca", - "freedom": "@txt.freedommobile.ca", - "koodo": "@msg.koodomobile.com", - "public_mobile": "@msg.telus.com", - "telus": "@msg.telus.com", - "rogers": "@pcs.rogers.com", - "sasktel": "@sms.sasktel.com", - "speakout": "@pcs.rogers.com", - "virgin_ca": "@vmobile.ca" - } # Smtp self.smtp = None @@ -217,8 +193,8 @@ def init_server(self): raise PySMSException("Unable to start IMAP server, please check address and SSL/TLS settings.") def add_number(self, number, carrier): - if carrier in self.carriers: - address = number + self.carriers[carrier] + if carrier in constants.CARRIERS: + address = number + constants.CARRIERS[carrier] self.addresses[number] = address self.logger.info("Number: {0} added.".format(number)) else: @@ -447,4 +423,3 @@ def text(self, msg, address=None, callback=False): self.logger.debug("Message: \"{message}\" sent to: {address} unsuccessfully.".format(message=msg, address=address)) ret.append(success) return ret - diff --git a/PySMS3.py b/PySMS3.py index dde34c0..25d324f 100644 --- a/PySMS3.py +++ b/PySMS3.py @@ -4,7 +4,7 @@ import dataclasses import logging -from typing import Sequence, Optional +from typing import Sequence, Optional, Callable import smtplib import email import email.policy @@ -46,12 +46,14 @@ def __init__(self, host: str, port: int, address: str, password: str, ssl: bool self.init_smtp(host=self.host, port=self.port, ssl=self.ssl) def init_smtp(self, host: str, port: int, ssl: bool): - if ssl: - self.smtp_client = smtplib.SMTP_SSL(host=host, port=port) - else: - self.smtp_client = smtplib.SMTP(host=host, port=port) - # TODO(clayshieh): error handling - self.smtp_client.login(self.address, self.password) + try: + if ssl: + self.smtp_client = smtplib.SMTP_SSL(host=host, port=port) + else: + self.smtp_client = smtplib.SMTP(host=host, port=port) + self.smtp_client.login(self.address, self.password) + except smtplib.SMTPException as e: + raise PySMS3Exception(f"Unable to start smtp server, please check credentials. Error: {e}") def send_message(self, addresses: Sequence[str], msg: str): """Sends an email via the smtp client.""" @@ -74,3 +76,22 @@ def send_text_message(self, phone_numbers: Sequence[PhoneNumber], msg: str, igno else: raise PySMS3Exception(f"Failed to convert phone number:") return self.send_message(addresses=converted_addresses, msg=msg) + + def send_text_message_with_callback(self, phone_numbers: Sequence[PhoneNumber], msg: str, callback: Callable[[str, str], None], ignore_failures: bool = False): + """Sends a message as a text message with a callback function after converting the phone number into the equivalent email address.""" + converted_addresses = list() + for pn in phone_numbers: + if converted_addr := convert_number_to_email(phone_number=pn.number, carrier=pn.carrier): + converted_addresses.append(converted_addr) + elif ignore_failures: + logger.warning(f"Failed to convert phone number: {pn}, skipping.") + continue + else: + raise PySMS3Exception(f"Failed to convert phone number:") + + # Send the message + self.send_message(addresses=converted_addresses, msg=msg) + + # Execute the callback function + for address in converted_addresses: + callback(address, msg) diff --git a/README.md b/README.md index f12bcb1..aa9eaa1 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,47 @@ Value was: Amazing Additional settings such as the window time, delimiter and identifier length can be configured when you initialize the server object by setting the optional arguments `window`, `delimiter` and `identifier_length` repsectively. +### Using PySMS3 for Python 3 + +To use the PySMS3 class for sending SMS via email using Python 3, follow the instructions below: + +1. Import the necessary modules: + +```python +import PySMS3 +from PySMS3 import PhoneNumber +``` + +2. Initialize the PySMS3 client with your address, password, smtp_server, smtp_port, and an optional ssl flag: + +```python +ps = PySMS3.PySMS3(host="smtp.example.com", port=465, address="text@example.com", password="password", ssl=True) +``` + +3. Create a list of PhoneNumber objects with the phone numbers and their corresponding carriers: + +```python +phone_numbers = [ + PhoneNumber(number="5551231234", carrier="att"), + PhoneNumber(number="5559876543", carrier="verizon") +] +``` + +4. Send a text message to the list of phone numbers: + +```python +ps.send_text_message(phone_numbers, "This is a text message!") +``` + +5. Send a text message with a callback function: + +```python +def callback_function(address, msg): + print(f"Message sent to {address}: {msg}") + +ps.send_text_message_with_callback(phone_numbers, "This is a text message with a callback!", callback_function) +``` + ### Acknowledgements Referenced https://www.digitaltrends.com/mobile/how-to-send-e-mail-to-sms-text/ for emails for each US carrier in `self.carriers`