Sending 9000/s push notifications for iOS - python

My system has about 10000 iOS users and i want to send them a push notification but without taking time as i may send another message after 5 minutes or less for the same user,
I read this answer before which also founded in Apple Site:
Push Notification Throughput and Error Checking
There are no caps or batch size limits for using APNs. The iOS 6.1
press release stated that APNs has sent over 4 trillion push
notifications since it was established. It was announced at WWDC 2012
that APNs is sending 7 billion notifications daily.
If you're seeing throughput lower than 9,000 notifications per second,
your server might benefit from improved error handling logic.
But a don't know how to send 9000/s message while i'm sending the notification one by one.
I'm using Python (PyAPNs) and this is my code:
from apns import APNs,Payload
result = execute("SELECT token_hex FROM `Users`")
for row in result:
token_hex = row['token_hex']
apns = APNs(use_sandbox=False, cert_file='Cert.pem', key_file='CertKey.pem')
payload = Payload(alert="Message",badge=1,sound='default')
apns.gateway_server.send_notification(token_hex, payload)
I'm sending to 10000 users in more than 30 minutes...
So what is the problem in my code or what can i do to send the notification in less time...
Thanks in Advance,

I don't know python but looking at your code it looks like you are duplicating calls unnecessarily. You should use the same connection for sending all the notifications.
Perhaps you should try something like this :
from apns import APNs,Payload
result = execute("SELECT token_hex FROM `Users`")
apns = APNs(use_sandbox=False, cert_file='Cert.pem', key_file='CertKey.pem')
payload = Payload(alert="Message",badge=1,sound='default')
for row in result:
token_hex = row['token_hex']
apns.gateway_server.send_notification(token_hex, payload)
This is assuming you are sending the same notification payload to all your devices.

Related

Receive message of any user in python ejabberd using xmlrpc.client

I am using ejabberd in python and I found a method to send the messages but how to get them messages or receive those messages in my python console please suggest me some method or way to do this.
to send the message my code is
import xmlrpc.client as xmlrpclib
server_url = 'http://127.0.0.1:5180/xmlrpc/'
server = xmlrpclib.ServerProxy(server_url)
EJABBERD_XMLRPC_LOGIN = {'user':'yatish', 'server':'localhost', 'password':'1234', 'admin':False}
def ejabberdctl(command, data):
fn = getattr(server, command)
print(fn.__dict__,'>>>>>>>>>>')
return fn(EJABBERD_XMLRPC_LOGIN, data)
result = ejabberdctl('send_message', {"type":"chat","from":"yatish#localhost","to":"1#localhost",
"subject":"backend subject","body":"Hey this is message from python1"})
here I can send messages from yatish#localhost to 1#localhost user I want to get all the messages received of the 1#lcoalhost, can you please suggest me some method I have checked all the docs and google by my side but unable to get some ay to receive all those messages in python. if the messages received the client should connected and receive the messages relatime.
thanks
You wrote a XMLRPC client to use the ejabberd's "send_message" administrative command to perform this task.
But there isn't any admin command in ejabberd to check or read XMPP messages.
I suggest you a different approach: forget about using XMLRPC or ejabberd commands. Instead, write a small XMPP client (there are libraries in python for that, see https://xmpp.org/software/libraries/ ).
Your XMPP client should:
login to the FROM account
send the message
logout
Then write another small client that
logins to the TO account, with a possitive presence number
ejabberd will immediately send him the offline messages that were stored
do whatever with those messages, and logout
If you are able to write those XMPP clients in your prefered language (Python or whatever), you can use those clients with any XMPP server: ejabberd, or any other that you may want to install in other machines, or in the future.

Twilio Outbound SMS Message Not Delivered

I'm using the following code to send an outbound SMS message from Twilio:
from twilio.rest import Client
account_sid = '<ACCOUNT SID>'
auth_token = '<AUTH TOKEN>'
client = Client(account_sid, auth_token)
message = client.messages.create(to='<To mobile number>',
from_='<Twilio phone number>',
body='Stackoverflow is awesome!')
print('Message ID: ' + message.sid)
The code worked fine for my mobile number i.e. the messages are received on my phone and the Programmable Messaging Log shows the status Delivered. All good!
However, some of my friends/colleagues couldn't receive messages on their phones. When I checked the Programmable Messaging Logs, it shows the status Sent (and not Delivered). I couldn't figure out the possible issue and a working solution to this problem.
Any guidance will be really appreciated.
The issue is resolved.
The Sent status of the messages that were not delivered eventually turned to Undelivered (Error: 30008) Unknown error. I went through this page and read about possible solutions to resolve Error 30008. Eventually, I figured out that I was using an exclamation mark (!) in the body text that was causing the problem. I removed the exclamation mark and the SMS was delivered successfully.

Python aiosmtpd - what is missing for an Mail-Transfer-Agent (MTA)?

I want to write my own small mailserver application in python with aiosmtpd
a) for educational purpose to better understand mailservers
b) to realize my own features
So my question is, what is missing (besides aiosmtpd) for an Mail-Transfer-Agent, that can send and receive emails to/from other full MTAs (gmail.com, yahoo.com ...)?
I'm guessing:
1.) Of course a domain and static ip
2.) Valid certificate for this domain
...should be doable with Lets Encrypt
3.) Encryption
...should be doable with SSL/Context/Starttls... with aiosmtpd itself
4.) Resolving MX DNS entries for outgoing emails!?
...should be doable with python library dnspython
5.) Error handling for SMTP communication errors, error replies from other MTAs, bouncing!?
6.) Queue for handling inbound and pending outbund emails!?
Are there any other "essential" features missing?
Of course i know, there are a lot more "advanced" features for a mailserver like spam checking, malware checking, certificate validation, blacklisting, rules, mailboxes and more...
Thanks for all hints!
EDIT:
Let me clarify what is in my mind:
I want to write a mailserver for a club. Its main purpose will be a mailing-list-server. There will be different lists for different groups of the club.
Lets say my domain is myclub.org then there will be for example youth#myclub.org, trainer#myclub.org and so on.
Only members will be allowed to use this mailserver and only the members will receive emails from this mailserver. No one else will be allowed to send emails to this mailserver nor will receive emails from it. The members email-addresses and their group(s) are stored in a database.
In the future i want to integrate some other useful features, for example:
Auto-reminders
A chatbot, where members can control services and request informations by email
What i don't need:
User Mailboxes
POP/IMAP access
Webinterface
Open relay issue:
I want to reject any [FROM] email address that is not in the members database during SMTP negotiation.
I want to check the sending mailservers for a valid certificate.
The number of emails/member/day will be limited.
I'm not sure, if i really need spam detection for the incoming emails?
Losing emails issue:
I think i will need a "lightweight" retry mechanism. However if an outgoing email can't be delivered after some retries, it will be dropped and only the administrator will be notified, not the sender. The members should not be bothered by email delivery issues. Is there any Python Library that can generate RFC3464 compliant error reply emails?
Reboot issue:
I'm not sure if i really need persistent storage for emails, that are not yet sent? In my use case, all the outgoing emails should be delivered usually within a few seconds (if no delivery problem occurs). Before a (planned) reboot i can check for an empty send queue.
aiosmtpd is an excellent tool for writing custom routing and header rewriting rules for email. However, aiosmtpd is not an MTA, since it does not do message queuing or DSN generation. One popular choice of MTA is postfix, and since postfix can be configured to relay all emails for a domain to another local SMTP server (such as aiosmtpd), a natural choice is to use postfix as the internet-facing frontend and aiosmtpd as the business-logic backend.
Advantages of using postfix as the middle-man instead of letting aiosmtpd face the public internet:
No need to handle DNS MX lookups in aiosmtpd -- just relay through postfix (localhost:25)
No worry about non-compliant SMTP clients in aiosmtpd
No worry about STARTTLS in aiosmtpd -- configure this in postfix instead (simpler and more battle-hardened)
No worry about retrying failed email deliveries and sending delivery status notifications
aiosmtpd can be configured to respond with "transient failure" (SMTP 4xx code) upon programming errors, so no email is lost as long as the programming error is fixed within 4 days
Here's how you might configure postfix to work with a local SMTP server powered by e.g. aiosmtpd.
We're going to run postfix on port 25 and aiosmtpd on port 20381.
To specify that postfix should relay emails for example.com to an SMTP server running on port 20381, add the following to /etc/postfix/main.cf:
transport_maps = hash:/etc/postfix/smtp_transport
relay_domains = example.com
And create /etc/postfix/smtp_transport with the contents:
# Table of special transport method for domains in
# virtual_mailbox_domains. See postmap(5), virtual(5) and
# transport(5).
#
# Remember to run
# postmap /etc/postfix/smtp_transport
# and update relay_domains in main.cf after changing this file!
example.com smtp:127.0.0.1:20381
Run postmap /etc/postfix/smtp_transport after creating that file (and every time you modify it).
On the aiosmtpd side, there are a few things to consider.
The most important is how you handle bounce emails. The short story is that you should set the envelope sender to an email address you control that is dedicated to receiving bounces, e.g. bounce#example.com. When email arrives at this address, it should be stored somewhere so you can process bounces, e.g. by removing member email addresses from your database.
Another important thing to consider is how you tell your members' email providers that you are doing mailing list forwarding. You might want to add the following headers when forwarding emails to GROUP#example.com:
Sender: bounce#example.com
List-Name: GROUP
List-Id: GROUP.example.com
List-Unsubscribe: <mailto:postmaster#example.com?subject=unsubscribe%20GROUP>
List-Help: <mailto:postmaster#example.com?subject=list-help>
List-Subscribe: <mailto:postmaster#example.com?subject=subscribe%20GROUP>
Precedence: bulk
X-Auto-Response-Suppress: OOF
Here, I used postmaster#example.com as the recipient for list unsubscribe requests. This should be an address that forwards to the email administrator (that is, you).
Below is a skeleton (untested) that does the above. It stores bounce emails in a directory named bounces and forwards emails with a valid From:-header (one that appears in MEMBERS) according to the list of groups (in GROUPS).
import os
import email
import email.utils
import mailbox
import smtplib
import aiosmtpd.controller
LISTEN_HOST = '127.0.0.1'
LISTEN_PORT = 20381
DOMAIN = 'example.com'
BOUNCE_ADDRESS = 'bounce'
POSTMASTER = 'postmaster'
BOUNCE_DIRECTORY = os.path.join(
os.path.dirname(__file__), 'bounces')
def get_extra_headers(list_name, is_group=True, skip=()):
list_id = '%s.%s' % (list_name, DOMAIN)
bounce = '%s#%s' % (BOUNCE_ADDRESS, DOMAIN)
postmaster = '%s#%s' % (POSTMASTER, DOMAIN)
unsub = '<mailto:%s?subject=unsubscribe%%20%s>' % (postmaster, list_name)
help = '<mailto:%s?subject=list-help>' % (postmaster,)
sub = '<mailto:%s?subject=subscribe%%20%s>' % (postmaster, list_name)
headers = [
('Sender', bounce),
('List-Name', list_name),
('List-Id', list_id),
('List-Unsubscribe', unsub),
('List-Help', help),
('List-Subscribe', sub),
]
if is_group:
headers.extend([
('Precedence', 'bulk'),
('X-Auto-Response-Suppress', 'OOF'),
])
headers = [(k, v) for k, v in headers if k.lower() not in skip]
return headers
def store_bounce_message(message):
mbox = mailbox.Maildir(BOUNCE_DIRECTORY)
mbox.add(message)
MEMBERS = ['foo#example.net', 'bar#example.org',
'clubadmin#example.org']
GROUPS = {
'group1': ['foo#example.net', 'bar#example.org'],
POSTMASTER: ['clubadmin#example.org'],
}
class ClubHandler:
def validate_sender(self, message):
from_ = message.get('From')
if not from_:
return False
realname, address = email.utils.parseaddr(from_)
if address not in MEMBERS:
return False
return True
def translate_recipient(self, local_part):
try:
return GROUPS[local_part]
except KeyError:
return None
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
local, domain = address.split('#')
if domain.lower() != DOMAIN:
return '550 wrong domain'
if local.lower() == BOUNCE:
envelope.is_bounce = True
return '250 OK'
translated = self.translate_recipient(local.lower())
if translated is None:
return '550 no such user'
envelope.rcpt_tos.extend(translated)
return '250 OK'
async def handle_DATA(self, server, session, envelope):
if getattr(envelope, 'is_bounce', False):
if len(envelope.rcpt_tos) > 0:
return '500 Cannot send bounce message to multiple recipients'
store_bounce_message(envelope.original_content)
return '250 OK'
message = email.message_from_bytes(envelope.original_content)
if not self.validate_sender(message):
return '500 I do not know you'
for header_key, header_value in get_extra_headers('club'):
message[header_key] = header_value
bounce = '%s#%s' % (BOUNCE_ADDRESS, DOMAIN)
with smtplib.SMTP('localhost', 25) as smtp:
smtp.sendmail(bounce, envelope.rcpt_tos, message.as_bytes())
return '250 OK'
if __name__ == '__main__':
controller = aiosmtpd.controller.Controller(ClubHandler, hostname=LISTEN_HOST, port=LISTEN_PORT)
controller.start()
print("Controller started")
try:
while True:
input()
except (EOFError, KeyboardInterrupt):
controller.stop()
The most important thing about running your own SMTP server is that you must not be an open relay. That means you must not accept messages from strangers and relay them to any destination on the internet, since that would enable spammers to send spam through your SMTP server -- which would quickly get you blocked.
Thus, your server should
relay from authenticated users/senders to remote destinations, or
relay from strangers to your own domains.
Since your question talks about resolving MX records for outgoing email, I'm assuming you want your server to accept emails from authenticated users. Thus you need to consider how your users will authenticate themselves to the server. aiosmtpd currently has an open pull request providing a basic SMTP AUTH implementation; you may use that, or you may implement your own (by subclassing aiosmtpd.smtp.SMTP and implementing the smtp_AUTH() method).
The second-most important thing about running your own SMTP server is that you must not lose emails without notifying the sender. When you accept an email from an authenticated user to be relayed to an external destination, you should let the user know (by sending an RFC 3464 Delivery Status Notification via email) if the message is delayed or if it is not delivered at all.
You should not drop the email immediately if the remote destination fails to receive it; you should try again later and repeatedly try until you deem that you have tried for long enough. Postfix, for instance, waits 10 minutes before trying to deliver the email after the first delivery attempt fails, and then it waits 20 minutes if the second attempt fails, and so on until the message has been attempted delivered for a couple days.
You should also take care to allow the host running your mail server to be rebooted, meaning you should store queued messages on disk. For this you might be able to use the mailbox module.
Of course, I haven't covered every little detail, but I think the above two points are the most important, and you didn't seem to cover them in your question.
You may consider the following features:
Message threading
Support for Delivery status
Support for POP and IMAP protocols
Supports for protocols such as RFC 2821 SMTP and RFC 2033 LMTP email message transport
Support Multiple message tagging
Support for PGP/MIME (RFC2015)
Support list-reply
Lets each user manage their own mail lists Supports
Control of message headers during composition
Support for address groups
Prevention of mailing list loops
Junk mail control

How can I send a push notification without prompting the password each time?

I am using the apns library to send push notifications to my iPhone. While I'm successfully receiving push notifications to my device, the script asks for the Certificate password every time I run it to send a push notification. I'm trying to figure out a way to include the password somehow in the code but have been unsuccessful so far.
I'm running the example code from their repository:
from apns import APNs, Payload
apns = APNs(use_sandbox=True, cert_file='TestCert.pem', key_file='TestKey.pem')
# Send a notification
token_hex = '<token hidden for obvious reasons>'
payload = Payload(alert="Hello World!", sound="default", badge=1)
apns.gateway_server.send_notification(token_hex, payload)
I've also been checking the library source code but it doesn't seem to have any useful option.
I've finally found a decent solution on the answer to this question.
I've also found out that from Python 3.3 it's possible to use the password adding the method SSLContext.load_cert_chain(certfile, keyfile, password) in the function that opens the SSL connection.

App engine Channel API returns no messages

Problem description: channel messages no returned to ajax script.
Initially, messages are delivered to clietn side, but the problem appears when I set larger timeout in js:
goog.appengine.Socket.POLLING_TIMEOUT_MS = 5000; //poll every 5 seconds
I've added a very basic Python code to test if Channel API works in my Google App Engine app.
index:
token = channel.create_channel(CHANNEL_NAME)
channel.send_message(CHANNEL_NAME, message)
#token is passed to template
additional_view:
#is another view, trigger manually from browser after index
from django.utils import simplejson
channel.send_message(CHANNEL_NAME, simplejson.dumps(data))
At client side I have a regular js with onMessage code.
The problem is that no messages are returned to client-side requests. They all come empty to polling ajax (as seen in Firebug). In application log I can see that channel is created:
"Creating channel token channel-2382918168-broadcast with client id broadcast"
and later message is sent but with a comment:
in between come these requests:
INFO 2011-08-03 14:33:32,000 dev_appserver.py:4248] "POST /_ah/channel/connected/ HTTP/1.1" 404 -
INFO 2011-08-03 14:33:33,780 dev_appserver.py:4248] "POST /_ah/channel/disconnected/ HTTP/1.1" 404 -
** ....message text...to channel with key (broadcast): no clients connected***
How does channel/message function at deeper level? Are messages lost if no clients are connected or they are retrived by newly connect clients?
If for some reason I create a channel with the same name, would it distroy undelivered messages it has inside?
Stay away from setting the POLLING_TIMEOUT_MS higher than 1.5 sec, the dev_appserver will assume you have disconnected.
It does not work via polling in production, so you do not have to worry about the timeout really.
Edit: just saw Robert's comment; personally I have even had issues if I set the polling to 3sec in Chrome/Safari/Firefox. I now just have ?disable_channel=true query strings on my apps so that I can run them without setting my laptop on fire with the CPU usage.

Categories