Ticket #4572: smtpclient.xhtml.patch

File smtpclient.xhtml.patch, 17.0 KB (added by jdb, 6 years ago)
  • doc/mail/tutorial/smtpclient/smtpclient.xhtml

    diff --git a/doc/mail/tutorial/smtpclient/smtpclient.xhtml b/doc/mail/tutorial/smtpclient/smtpclient.xhtml
    index aea44ba..9e89a84 100644
    a b files.</p> 
    2929<h3>SMTP Client 1</h3>
    3030
    3131<p>The first step is to create <a href="smtpclient-1.tac">the most
    32 minimal <code>.tac</code> file</a> possible for use by
    33 <code>twistd</code>.</p>
     32minimal <code>.tac</code> file</a> possible for use by <code>twistd</code> .</p>
    3433
    3534<pre class="python">
    3635from twisted.application import service
    3736</pre>
    3837
    39 <p>The first line of the <code>.tac</code> file imports
    40 <code>twisted.application.service</code>, a module which contains many
    41 of the basic <em>service</em> classes and helper functions available
    42 in Twisted.  In particular, we will be using the
    43 <code>Application</code> function to create a new <em>application
     38<p>The first line of the <code>.tac</code> file
     39imports <code>twisted.application.service</code>, a module which
     40contains many of the basic <em>service</em> classes and helper
     41functions available in Twisted.  In particular, we will be using
     42the <code>Application</code> function to create a new <em>application
    4443service</em>.  An <em>application service</em> simply acts as a
    4544central object on which to store certain kinds of deployment
    4645configuration.</p>
    configuration.</p> 
    4948application = service.Application("SMTP Client Tutorial")
    5049</pre>
    5150
    52 <p>The second line of the <code>.tac</code> file creates a new
    53 <em>application service</em> and binds it to the local name
    54 <code>application</code>.  <code>twistd</code> requires this local
    55 name in each <code>.tac</code> file it runs.  It uses various pieces
    56 of configuration on the object to determine its behavior.  For
     51<p>The second line of the <code>.tac</code> file creates a
     52new <em>application service</em> and binds it to the local
     53name <code>application</code>.  <code>twistd</code> requires this
     54local name in each <code>.tac</code> file it runs.  It uses various
     55pieces of configuration on the object to determine its behavior.  For
    5756example, <code>"SMTP Client Tutorial"</code> will be used as the name
    5857of the <code>.tap</code> file into which to serialize application
    5958state, should it be necessary to do so.</p>
    6059
    61 <p>That does it for the first example.  We now have enough of a
    62 <code>.tac</code> file to pass to <code>twistd</code>.  If we run <a
    63 href="smtpclient-1.tac">smtpclient-1.tac</a> using the
    64 <code>twistd</code> command line:</p>
     60<p>That does it for the first example.  We now have enough of
     61a <code>.tac</code> file to pass to <code>twistd</code>.  If we
     62run <a href="smtpclient-1.tac">smtpclient-1.tac</a> using
     63the <code>twistd</code> command line:</p>
    6564
    6665<pre class="python">
    6766twistd -ny smtpclient-1.tac
    from twisted.application import internet 
    101100from twisted.internet import protocol
    102101</pre>
    103102
    104 <p><code>twisted.application.internet</code> is another
    105 <em>application service</em> module.  It provides services for
     103<p><code>twisted.application.internet</code> is
     104another <em>application service</em> module.  It provides services for
    106105establishing outgoing connections (as well as creating network
    107 servers, though we are not interested in those parts for the moment).
    108 <code>twisted.internet.protocol</code> provides base implementations
    109 of many of the core Twisted concepts, such as <em>factories</em> and
    110 <em>protocols</em>.</p>
     106servers, though we are not interested in those parts for the
     107moment). <code>twisted.internet.protocol</code> provides base
     108implementations of many of the core Twisted concepts, such
     109as <em>factories</em> and <em>protocols</em>.</p>
    111110
    112111<p>The next line of <a href="smtpclient-2.tac">smtpclient-2.tac</a>
    113112instantiates a new <em>client factory</em>.</p>
    instantiates a new <em>client factory</em>.</p> 
    116115smtpClientFactory = protocol.ClientFactory()
    117116</pre>
    118117
    119 <p><em>Client factories</em> are responsible for constructing
    120 <em>protocol instances</em> whenever connections are established.
    121 They may be required to create just one instance, or many instances if
    122 many different connections are established, or they may never be
    123 required to create one at all, if no connection ever manages to be
    124 established.</p>
     118<p><em>Client factories</em> are responsible for
     119constructing <em>protocol instances</em> whenever connections are
     120established.  They may be required to create just one instance, or
     121many instances if many different connections are established, or they
     122may never be required to create one at all, if no connection ever
     123manages to be established.</p>
    125124
    126125<p>Now that we have a client factory, we'll need to hook it up to the
    127126network somehow.  The next line of <code>smtpclient-2.tac</code> does
    just that:</p> 
    131130smtpClientService = internet.TCPClient(None, None, smtpClientFactory)
    132131</pre>
    133132
    134 <p>We'll ignore the first two arguments to
    135 <code>internet.TCPClient</code> for the moment and instead focus on
     133<p>We'll ignore the first two arguments
     134to <code>internet.TCPClient</code> for the moment and instead focus on
    136135the third.  <code>TCPClient</code> is one of those <em>application
    137136service</em> classes.  It creates TCP connections to a specified
    138137address and then uses its third argument, a <em>client factory</em>,
    139138to get a <em>protocol instance</em>.  It then associates the TCP
    140139connection with the protocol instance and gets out of the way.</p>
    141140
    142 <p>We can try to run <code>smtpclient-2.tac</code> the same way we ran
    143 <code>smtpclient-1.tac</code>, but the results might be a little
     141<p>We can try to run <code>smtpclient-2.tac</code> the same way we
     142ran <code>smtpclient-1.tac</code>, but the results might be a little
    144143disappointing:</p>
    145144
    146145<pre class="shell">
    something with a bit more meaning:</p> 
    198197smtpClientService = internet.TCPClient('localhost', 25, smtpClientFactory)
    199198</pre>
    200199
    201 <p>This directs the client to connect to <em>localhost</em> on port
    202 <em>25</em>.  This isn't the address we want ultimately, but it's a
    203 good place-holder for the time being.  We can run <a
    204 href="smtpclient-3.tac">smtpclient-3.tac</a> and see what this change
    205 gets us:</p>
     200<p>This directs the client to connect to <em>localhost</em> on
     201port <em>25</em>.  This isn't the address we want ultimately, but it's
     202a good place-holder for the time being.  We can
     203run <a href="smtpclient-3.tac">smtpclient-3.tac</a> and see what this
     204change gets us:</p>
    206205
    207206<pre class="shell">
    208207exarkun@boson:~/mail/tutorial/smtpclient$ twistd -ny smtpclient-3.tac
    exarkun@boson:~/mail/tutorial/smtpclient$ 
    246245</pre>
    247246
    248247<p>A meagre amount of progress, but the service still raises an
    249 exception.  This time, it's because we haven't specified a
    250 <em>protocol class</em> for the factory to use.  We'll do that in the
    251 next example.</p>
     248exception.  This time, it's because we haven't specified
     249a <em>protocol class</em> for the factory to use.  We'll do that in
     250the next example.</p>
    252251
    253252<h3>SMTP Client 4</h3>
    254253
    exarkun@boson:~/doc/mail/tutorial/smtpclient$ twistd -ny smtpclient-4.tac 
    288287exarkun@boson:~/doc/mail/tutorial/smtpclient$
    289288</pre>
    290289
    291 <p>But what does this mean?
    292 <code>twisted.internet.protocol.Protocol</code> is the base
    293 <em>protocol</em> implementation.  For those familiar with the classic
    294 UNIX network services, it is equivalent to the <em>discard</em>
    295 service.  It never produces any output and it discards all its input.
    296 Not terribly useful, and certainly nothing like an SMTP client.  Let's
    297 see how we can improve this in the next example.</p>
     290<p>But what does this
     291mean? <code>twisted.internet.protocol.Protocol</code> is the
     292base <em>protocol</em> implementation.  For those familiar with the
     293classic UNIX network services, it is equivalent to
     294the <em>discard</em> service.  It never produces any output and it
     295discards all its input.  Not terribly useful, and certainly nothing
     296like an SMTP client.  Let's see how we can improve this in the next
     297example.</p>
    298298
    299299<h3>SMTP Client 5</h3>
    300300
    301301<p>In <a href="smtpclient-5.tac">smtpclient-5.tac</a>, we will begin
    302302to use Twisted's SMTP protocol implementation for the first time.
    303 We'll make the obvious change, simply swapping out
    304 <code>twisted.internet.protocol.Protocol</code> in favor of
    305 <code>twisted.mail.smtp.ESMTPClient</code>.  Don't worry about the
    306 <em>E</em> in <em>ESMTP</em>.  It indicates we're actually using a
    307 newer version of the SMTP protocol.  There is an
    308 <code>SMTPClient</code> in Twisted, but there's essentially no reason
    309 to ever use it.</p>
     303We'll make the obvious change, simply swapping
     304out <code>twisted.internet.protocol.Protocol</code> in favor
     305of <code>twisted.mail.smtp.ESMTPClient</code>.  Don't worry about
     306the <em>E</em> in <em>ESMTP</em>.  It indicates we're actually using a
     307newer version of the SMTP protocol.  There is
     308an <code>SMTPClient</code> in Twisted, but there's essentially no
     309reason to ever use it.</p>
    310310
    311311<p>smtpclient-5.tac adds a new import:</p>
    312312
    to ever use it.</p> 
    314314from twisted.mail import smtp
    315315</pre>
    316316
    317 <p>All of the mail related code in Twisted exists beneath the
    318 <code>twisted.mail</code> package.  More specifically, everything
    319 having to do with the SMTP protocol implementation is defined in the
    320 <code>twisted.mail.smtp</code> module.</p>
     317<p>All of the mail related code in Twisted exists beneath
     318the <code>twisted.mail</code> package.  More specifically, everything
     319having to do with the SMTP protocol implementation is defined in
     320the <code>twisted.mail.smtp</code> module.</p>
    321321
    322322<p>Next we remove a line we added in smtpclient-4.tac:</p>
    323323
    exarkun@boson:~/doc/mail/tutorial/smtpclient$ 
    379379
    380380<p>Oops, back to getting a traceback.  This time, the default
    381381implementation of <code>buildProtocol</code> seems no longer to be
    382 sufficient.  It instantiates the protocol with no arguments, but
    383 <code>ESMTPClient</code> wants at least one argument.  In the next
     382sufficient.  It instantiates the protocol with no arguments,
     383but <code>ESMTPClient</code> wants at least one argument.  In the next
    384384version of the client, we'll override <code>buildProtocol</code> to
    385385fix this problem.</p>
    386386
    387387<h3>SMTP Client 6</h3>
    388388
    389 <p><a href="smtpclient-6.tac">smtpclient-6.tac</a> introduces a
    390 <code>twisted.internet.protocol.ClientFactory</code> subclass with an
    391 overridden <code>buildProtocol</code> method to overcome the problem
    392 encountered in the previous example.</p>
     389<p><a href="smtpclient-6.tac">smtpclient-6.tac</a> introduces
     390a <code>twisted.internet.protocol.ClientFactory</code> subclass with
     391an overridden <code>buildProtocol</code> method to overcome the
     392problem encountered in the previous example.</p>
    393393
    394394<pre class="python">
    395395class SMTPClientFactory(protocol.ClientFactory):
    will now instantiate <code>SMTPClientFactory</code>:</p> 
    421421smtpClientFactory = SMTPClientFactory()
    422422</pre>
    423423
    424 <p>Running this version of the code, we observe that the code
    425 <strong>still</strong> isn't quite traceback-free.</p>
     424<p>Running this version of the code, we observe that the
     425code <strong>still</strong> isn't quite traceback-free.</p>
    426426
    427427<pre class="shell">
    428428exarkun@boson:~/doc/mail/tutorial/smtpclient$ twistd -ny smtpclient-6.tac
    provide that information to it.</p> 
    484484actually includes message data to transmit.  For simplicity's sake,
    485485the message is defined as part of a new class.  In a useful program
    486486which sent email, message data might be pulled in from the filesystem,
    487 a database, or be generated based on user-input.  <a
    488 href="smtpclient-7.tac">smtpclient-7.tac</a>, however, defines a new
    489 class, <code>SMTPTutorialClient</code>, with three class attributes
    490 (<code>mailFrom</code>, <code>mailTo</code>, and
    491 <code>mailData</code>):</p>
     487a database, or be generated based on
     488user-input.  <a href="smtpclient-7.tac">smtpclient-7.tac</a>, however,
     489defines a new class, <code>SMTPTutorialClient</code>, with three class
     490attributes (<code>mailFrom</code>, <code>mailTo</code>,
     491and <code>mailData</code>):</p>
    492492
    493493<pre class="python">
    494494class SMTPTutorialClient(smtp.ESMTPClient):
    Twisted is <code>getMailData</code>:</p> 
    552552</pre>
    553553
    554554<p>This one is quite simple as well: it returns a file or a file-like
    555 object which contains the message contents.  In our case, we return a
    556 <code>StringIO</code> since we already have a string containing our
    557 message.  If the contents of the file returned by
    558 <code>getMailData</code> span multiple lines (as email messages often
    559 do), the lines should be <code>\n</code> delimited (as they would be
    560 when opening a text file in the <code>"rt"</code> mode): necessary
    561 newline translation will be performed by <code>SMTPClient</code>
    562 automatically.</p>
     555object which contains the message contents.  In our case, we return
     556a <code>StringIO</code> since we already have a string containing our
     557message.  If the contents of the file returned
     558by <code>getMailData</code> span multiple lines (as email messages
     559often do), the lines should be <code>\n</code> delimited (as they
     560would be when opening a text file in the <code>"rt"</code> mode):
     561necessary newline translation will be performed
     562by <code>SMTPClient</code> automatically.</p>
    563563
    564564<p>There is one more new callback method defined in smtpclient-7.tac.
    565565This one isn't for providing information about the messages to
    which starts up, connects to a (possibly) remote host, transmits some 
    587587data, and disconnects.  Notably missing, however, is application
    588588shutdown.  Hitting ^C is fine during development, but it's not exactly
    589589a long-term solution.  Fortunately, programmatic shutdown is extremely
    590 simple.  <a href="smtpclient-8.tac">smtpclient-8.tac</a> extends
    591 <code>sentMail</code> with these two lines:</p>
     590simple.  <a href="smtpclient-8.tac">smtpclient-8.tac</a>
     591extends <code>sentMail</code> with these two lines:</p>
    592592
    593593<pre class="python">
    594594        from twisted.internet import reactor
    def getMailExchange(host): 
    667667    return defer.succeed('localhost')
    668668</pre>
    669669
    670 <p><code>defer.succeed</code> is a function which creates a new
    671 <code>Deferred</code> which already has a result, in this case
    672 <code>'localhost'</code>.  Now we need to adjust our
    673 <code>TCPClient</code>-constructing code to expect and properly handle
    674 this <code>Deferred</code>:</p>
     670<p><code>defer.succeed</code> is a function which creates a
     671new <code>Deferred</code> which already has a result, in this
     672case <code>'localhost'</code>.  Now we need to adjust
     673our <code>TCPClient</code>-constructing code to expect and properly
     674handle this <code>Deferred</code>:</p>
    675675
    676676<pre class="python">
    677677def cbMailExchange(exchange):
    getMailExchange('example.net').addCallback(cbMailExchange) 
    687687scope of this document.  For such a look, see
    688688the <a href="../../../core/howto/defer.html">Deferred Reference</a>.
    689689However, in brief, what this version of the code does is to delay the
    690 creation of the <code>TCPClient</code> until the
    691 <code>Deferred</code> returned by <code>getMailExchange</code> fires.
    692 Once it does, we proceed normally through the creation of our
    693 <code>SMTPClientFactory</code> and <code>TCPClient</code>, as well as
    694 set the <code>TCPClient</code>'s service parent, just as we did in the
    695 previous examples.</p>
     690creation of the <code>TCPClient</code> until the <code>Deferred</code>
     691returned by <code>getMailExchange</code> fires.  Once it does, we
     692proceed normally through the creation of
     693our <code>SMTPClientFactory</code> and <code>TCPClient</code>, as well
     694as set the <code>TCPClient</code>'s service parent, just as we did in
     695the previous examples.</p>
    696696
    697697<h3>SMTP Client 11</h3>
    698698
    699699<p>At last we're ready to perform the mail exchange lookup.  We do
    700 this by calling on an object provided specifically for this task,
    701 <code>twisted.mail.relaymanager.MXCalculator</code>:</p>
     700this by calling on an object provided specifically for this
     701task, <code>twisted.mail.relaymanager.MXCalculator</code>:</p>
    702702
    703703<pre class="python">
    704704def getMailExchange(host):
    def getMailExchange(host): 
    710710<p>Because <code>getMX</code> returns a <code>Record_MX</code> object
    711711rather than a string, we do a little bit of post-processing to get the
    712712results we want.  We have already converted the rest of the tutorial
    713 application to expect a <code>Deferred</code> from
    714 <code>getMailExchange</code>, so no further changes are required.  <a
    715 href="smtpclient-11.tac">smtpclient-11.tac</a> completes this tutorial
    716 by being able to both look up the mail exchange host for the recipient
    717 domain, connect to it, complete an SMTP transaction, report its
    718 results, and finally shut down the reactor.</p>
    719 
    720 <!-- TODO: write a conclusion
    721 
    722 <h3>Conclusion</h3>
     713application to expect a <code>Deferred</code>
     714from <code>getMailExchange</code>, so no further changes are
     715required.  <a href="smtpclient-11.tac">smtpclient-11.tac</a> completes
     716this tutorial by being able to both look up the mail exchange host for
     717the recipient domain, connect to it, complete an SMTP transaction,
     718report its results, and finally shut down the reactor.</p>
    723719
    724 <p>XXX wrap it up</p>
     720<!-- TODO: write a conclusion to wrap it up -->
    725721
    726 -->
    727722</body>
    728723</html>