Posting a Message to an NNTP Server
While you're connected to an NNTP server, you can post messages to Usenet. Usenet articles are in the same basic format as email, but with some slightly stricter rules about required headers. You can read the full article format specification in RFC 1036 (http://www.faqs.org/rfc/rfc1036.txt). After you post an article through NNTP, your local NNTP server will pass it on to the other servers it knows about. From there, the article will continue to be passed from server to server until it's available throughout the Usenet network.
9.3.1. How Do I Do That?
Construct an article using the email.Message module (see Example 9-3). Select the newsgroup to which you'll be posting, and then post the article.
Example 9-3. nntppost.py
from twisted.news import nntp from twisted.internet import protocol, defer import time, email class NNTPPostProtocol(nntp.NNTPClient): def connectionMade(self): nntp.NNTPClient.connectionMade(self) self.fetchGroup(self.factory.newsgroup) def gotGroup(self, groupInfo): # post the article to the current newsgroup self.postArticle(self.factory.articleData) def postedOk(self): self.factory.deferred.callback(None) def postFailed(self, errorMessage): self.factory.deferred.errback(Exception(errorMessage)) def connectionLost(self, error): if not self.factory.deferred.called: self.factory.deferred.errback(error) class NNTPPostFactory(protocol.ClientFactory): protocol = NNTPPostProtocol def _ _init_ _(self, newsgroup, articleData): self.newsgroup = newsgroup self.articleData = articleData self.deferred = defer.Deferred( ) from email.Message import Message from email.Utils import make_msgid def makeArticle(sender, newsgroup, subject, body): article = Message( ) article["From"] = sender article["Newsgroups"] = newsgroup article["Subject"] = subject article["Message-Id"] = make_msgid( ) article.set_payload(body) return article.as_string(unixfrom=False) if __name__ == "_ _main_ _": from twisted.internet import reactor import sys def handleError(error): print >> sys.stderr, error.getErrorMessage( ) reactor.stop( ) if len(sys.argv) != 3: print >> sys.stderr, "Usage: %s server newsgroup" % sys.argv[0] sys.exit(1) server, newsgroup = sys.argv[1:3] sender = raw_input("From: ") subject = raw_input("Subject: ") bodyLines = [] while True: line = raw_input( ) if line == ".": break bodyLines.append(line) body = " ".join(bodyLines) articleData = makeArticle(sender, newsgroup, subject, body) print articleData factory = NNTPPostFactory(newsgroup, articleData) factory.deferred.addCallback( lambda _: reactor.stop( )).addErrback( handleError) reactor.connectTCP(server, 119, factory) reactor.run( )
Run nntppost.py with two arguments: the newsgroup and the NNTP server. It will prompt you to enter your article, connect to the server, and post your article to the newsgroup:
$ python nntppost.py alt.local.test localhost From: abe@fettig.net Subject: Test Message Enter article body below, followed by a single period: Hello Usenet World! . Posting message.... done!
|
9.3.2. How Does That Work?
In Example 9-3, the makeArticle function uses the email.Message.Message class to create an article in the proper format for posting to Usenet. It sets the following headers:
From
The email address of the person posting the article. This header is the same as in an email message.
Newsgroups
The list of newsgroups to which the article is being posted. If the message is being posted to multiple newsgroups, they should be separated by commas.
Subject
The subject, just like in an email message.
Message-Id
A globally unique identifier for this article, in the form . This is the same as the Message-Id header in an email message. It's important to use something truly unique, as the message ID will be used to identify this specific article as it moves from server to server in Usenet. The email.Utils module provides the helpful function make_msgid for generating unique message IDs.
Date
The date and time the article was created. This header is the same as in an email message. The function formatdate in email.Utils will take the floating-point number returned from time.time or time.gmtime and return a string in the proper format. If called with no arguments, as in Example 9-3, it returns the formatted current time.
The body of the article is a standard text message, which you add to the Message object using set_payload.
The NNTPPostProtocol class in Example 9-3 posts an article to the server using the postArticle method of nntp.NNTPClient. The postedOK method will be called if the article is posted successfully; the postFailed method will be called if it fails. Note that postArticle doesn't take the name of the newsgroup as an argument: the article will be posted to whatever newsgroups are listed in the Newsgroups header.