o bt@s\dZddlZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z ddl mZddlmZddlmZddlmZdd lmZmZmZmZdd lmZdd lmZmZdd lm Z m!Z!m"Z#dd l$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z6m7Z7ddl8m9Z9m:Z:m;Z;mm?Z?m@Z@ddlAmBZBmCZCddlDmEZEmFZFmGZGddlHmIZIgdZJeIKreLMdZNneOMdZNePQeRddZSdNddZTddZUeUZVdddfddZWd d!ZXd"\ZYZZZ[d#Z\Gd$d%d%Z]Gd&d'd'Z^Gd(d)d)e?j_e@j`ZaGd*d+d+ejbZcGd,d-d-e?jde@j`ZeGd.d/d/eeZfGd0d1d1eaZgGd2d3d3ZhGd4d5d5eheeZiGd6d7d7ejjZkGd8d9d9e#Z"ee9Gd:d;d;ZlGdd?d?ekZndd@edddAdAfdBdCZoddlpZpdOdDdEZqdOdFdGZrGdHdIdIepjsZtGdJdKdKepjuZvdLdMZwepxewdS)Pz/ Simple Mail Transfer Protocol implementation. N) parseaddr)BytesIO)Type) implementer)cred) longversion)defererrorprotocolreactor) _idnaText) ISSLTransport ITLSTransport)CramMD5ClientAuthenticatorLOGINAuthenticatorLOGINCredentials) AddressErrorAUTHDeclinedErrorAuthenticationErrorAUTHRequiredErrorEHLORequiredErrorESMTPClientErrorSMTPAddressError SMTPBadRcpt SMTPBadSenderSMTPClientErrorSMTPConnectErrorSMTPDeliveryError SMTPErrorSMTPProtocolErrorSMTPServerErrorSMTPTimeoutError SMTPTLSErrorTLSRequiredError)IClientAuthenticationIMessageDeliveryIMessageDeliveryFactory IMessageSMTP)basicpolicies)logutil) iterbytes nativeString networkString)platform)0rrrrrrrrrrrrrr r!TLSErrorr#rr$IMessager%r&rrrPLAINAuthenticatorAddressUsersendmail SenderMixinESMTP ESMTPClient ESMTPSenderESMTPSenderFactorySMTP SMTPClient SMTPFactory SMTPSenderSMTPSenderFactory idGenerator messageid quoteaddr rfc822datextextStreamReaderxtextStreamWriter xtext_codec xtext_decode xtext_encodeasciii,c Cs|s |r t}nt}|r9|drtj }ntj }tt|d\}}|r1|tt||9}t|d\}}nd\}}tdgd|d|dgd |d d |d |d |d |d||f S)a Format an RFC-2822 compliant date string. @param timeinfo: (optional) A sequence as returned by C{time.localtime()} or C{time.gmtime()}. Default is now. @param local: (optional) Indicates if the supplied time is local or universal time, or if no time is given, whether now should be local or universal time. Default is local, as suggested (SHOULD) by rfc-2822. @returns: A L{bytes} representing the time and date in RFC-2822 format. i<)rrz)%s, %02d %s %04d %02d:%02d:%02d %+03d%02d)MonTueWedThuFriSatSun) JanFebMarAprMayJunJulAugSepOctNovDecrKr) time localtimegmtimealtzonetimezonedivmodabsintr.)timeinfolocaltztzhrtzmintzsecrt3/usr/lib/python3/dist-packages/twisted/mail/smtp.pyrCs:    rCccsd} |V|d7}q)NrTrKrt)irtrtrur@s r@cCsttSN)next_genrtrtrtrusrzc CsVtdt}t}td}|durd}nd|}d|||||t  S)z Return a globally unique random string in RFC 2822 Message-ID format Optional uniq string will be added to strengthen uniqueness if given. z %Y%m%d%H%M%SiN.z<{}.{}.{}{}.{}@{}>) rfstrftimerhosgetpidrandom randrangeformatDNSNAMEdecodeencode)uniqNdatetimepidrandrtrtrurAs rAcCsdt|tr dt|dSt|tr|d}t|}|dkr'dt|dSd|dddS)zq Turn an email address, possibly with realname part etc, into a form suitable for and SMTP envelope. <>rINNrK) isinstancer3bytesrrr)addrresrtrtrurBs   rB)COMMANDDATAAUTHs[-A-Za-z0-9!\#$%&'*+/=?^_`{|}~]c@sveZdZdZededejZeeZ dddZ edZ dd Z d e fd d Zd efd dZd e fddZdS)r3aFParse and hold an RFC 2821 address. Source routes are stipped and ignored, UUCP-style bang-paths and %-style routing are not parsed. @type domain: C{bytes} @ivar domain: The domain within which this address resides. @type local: C{bytes} @ivar local: The local ("user") portion of this address. s( # A string of (?:"[^"]*" # quoted string |\\. # backslash-escaped characted |sL # atom character )+|.) # or any single characterNcCst|tr|j}t|tr|j|_dSt|ts!t|d}||_ t t d|j |}g}g}|r|ddkrL|ddkrEtd|dd}nv|ddkr|dd}|s}|rp|dd krp|dd}|rp|dd ksb|svtd |dd}nE|rtd d g}n;t|ddkr|j|ds|dd krtd|dd||f|s||dn||d|dd}|s5d ||_d ||_|jd kr|jd kr|durt}||_dSdSdS)NrIrrrz Unbalanced <>rK@:zMalformed source routez Too many @.zParse error at z of )rr4destr3__dict__copyrstrraddrstrlistfiltertstringsplitrlenatomrematchappendjoinrodomainr)selfr defaultDomainatlrorrtrtru__init__sT         ,    zAddress.__init__s\\(.)cCsg}t|tst|d}td|j|}|D],}|ddkr1|ddkr1||ddqd|vr@||j d|q||qd |S) z6 Remove RFC-2821 quotes from address. rINr"rrK\s\1r) rrrrrrrr dequotebssubr)rrrrtrtrtrudequoteJs   zAddress.dequotereturncC|dSNrI __bytes__rrrtrtru__str___zAddress.__str__cCs"|js|jrd|j|jfSdS)Nrr)rorrrrtrtrurbs zAddress.__bytes__cCsd|j|jjtt|S)Nz {}.{}({}))r __module__ __class____name__reprrrrtrtru__repr__hszAddress.__repr__rw)rr __qualname____doc__recompileatomXrrrrrrrrrrrtrtrtrur3s"   4r3c@s<eZdZdZddZddZdefddZdefd d Z d S) r4zu Hold information about and SMTP message recipient, including information on where the message came from cCs^z|j}Wn tyd}Ynwt|||_||_||_t|tr'||_dSt|||_dSrw)hostAttributeErrorr3rhelor rorig)r destinationrr rrrtrtrurts     z User.__init__cCs|j|jd|jdS)z Helper for pickle. protocol isn't picklabe, but we want User to be, so skip it in the pickle. N)rrr r)rrrrrtrtru __getstate__s zUser.__getstate__rcCrrrrrtrtrurrz User.__str__cCs t|jSrw)rrrrtrtrur zUser.__bytes__N) rrrrrrrrrrrtrtrtrur4ns  r4c@seZdZdZdZdZdZdZdZdZ dLddZ e ddZ e j d dZ d d Zd d ZddZdMddZddZddZddZddZddZddZdd Zd!d"Zd#ed$Zed%ed&ed'ejejBZ ed(ed&ed'ejejBZ!d)d*Z"dNd-d.Z#d/d0Z$d1d2Z%dOd4d5Z&d6d7Z'd8d9Z(d:d;Z)dd?Z+d@dAZ,e,Z-dBdCZ.dDdEZ/dFdGZ0dHdIZ1dJdKZ2dS)Pr;zp SMTP server-side protocol. @ivar host: The hostname of this mail server. @type host: L{bytes} XNTcCs.t|_d|_d|_g|_||_||_t|_dSrw) rmode_from_helo_todeliverydeliveryFactoryrr)rrrrtrtrurs z SMTP.__init__cCs|jSrw)_hostrrtrtrursz SMTP.hostcCs"t|ts t|d}||_dSr)rrrrr)rtoSetrtrtrurs  cCs$|jd}|d||jdS)Ns' Timeout. Try talking faster next time!i)rsendCode transportloseConnection)rmsgrtrtrutimeoutConnections  zSMTP.timeoutConnectioncCs |jdS)Ns NO UCE NO UBE NO RELAY PROBES)rrrtrtrugreetingrz SMTP.greetingcCsZ|j}z|j}Wn tyt|}Ynwd|f|_|d|||j dSN) rgetPeerrrrrrr setTimeouttimeout)rpeerrrtrtruconnectionMades     zSMTP.connectionMadercCsf|}|dd}|ddD]}|td|f|q|td|f|r-|dp.ddS)z3 Send an SMTP code with a message. rNz%3.3d-z%3.3d rr) splitlinessendLiner.)rcodemessagelineslastlinelinertrtrurs z SMTP.sendCodecCs|t|d|j|S)Nstate_) resetTimeoutgetattrrrrrtrtru lineReceivedszSMTP.lineReceivedcCs`|}|dd}|r*||dp|j}t|dkr$||ddS|ddS|dS)NrKrrVr)stripr lookupMethod do_UNKNOWNrsendSyntaxError)rrpartsmethodrtrtru state_COMMANDs    zSMTP.state_COMMANDcC|dddS)NsError: bad syntaxrrrtrtrurzSMTP.sendSyntaxErrorcCs&t|ts t|}t|d|dS)z @param command: The command to get from this class. @type command: L{str} @return: The function which executes this command. do_N)rrr-rupper)rcommandrtrtrurs zSMTP.lookupMethodcCs8|jtur|jD]}|qt|_|`|dddS)Nrs Line too long)rr_SMTP__messagesconnectionLostrr)rrrrtrtrulineLengthExceeded s   zSMTP.lineLengthExceededcCr)NrsCommand not implementedrrrestrtrtrurrzSMTP.do_UNKNOWNcCsx|j}z|j}Wn tyt|}Ynwt|ts"|d}||f|_d|_ g|_ | d|jd|ddS)Nidna Hello s, nice to meet you) rrrrrrrrrrrr)rrrrrtrtrudo_HELOs       z SMTP.do_HELOcCs|dd|jdS)Ns See you later)rrrrrtrtrudo_QUIT$s z SMTP.do_QUITs ("[^"]*"|\\.|s |[@.,:])+s>\s*FROM:\s*(?P<> # Empty <> | # |sq # addr )\s*(\s(?P.*))? # Optional WS + ESMTP options $s\s*TO:\s*(?P|D]}z|WqtytdtYqwdS)Nz(msg raised exception from connectionLost)r BaseExceptionr*rr )rmsgsrrtrtru _disconnects    zSMTP._disconnectc Cs\|jdus|js|dddSt|_|j|j}}|j}d|_g|_d|_g}|D]]\}}z|}||||g} | rA|| | |Wq*t yk} z|| j | j t |_||WYd} ~ dSd} ~ wtyt|ddt |_||YdSw||_d|_|_|dd|jrd} t| |d d |DfdSdS) Nrs'Must have valid receiver and originator&sInternal server errorrbsContinuez-Receiving message for delivery: from=%s to=%scSsg|]\}}t|qSrt)r).0ufrtrtru sz SMTP.do_DATA..)rrrrrr datafailedreceivedHeaderrrr rrrr/r-r*r r_SMTP__inheader _SMTP__inbodynoisyr) rrrorigin recipientsr.r(msgFuncrrcvdhdrrfmtrtrtrudo_DATAsJ          z SMTP.do_DATAc Csz|jtur,z|jD]}z|Wq tytYq w|`Wn ty+Ynw|jr6|d|_| ddSrw) rrrrr-r*r r _onLogoutr)rreasonrrtrtrurs      zSMTP.connectionLostcCsd|_g|_|dddS)NrsI remember nothing.)rrrrrtrtrudo_RSETsz SMTP.do_RSETc Cs4|dddkrC|dkr=t|_|jr||jj|jjdS|js(|ddStj dd|jDdd |j|`dS|dd}|jrHdSz1|j sg|j sgd|vrWd|_ n|rg|jD]}| d q\d|_ |sld|_ |jD]}| |qoWdSty}z||_|jD]}|qWYd}~dSd}~ww) NrKrz thrown awaycSsg|]}|qSrt) eomReceived)r2rrtrtrur5sz)SMTP.dataLineReceived..T) consumeErrorsrr)rrr6rrrr_messageHandledr DeferredList addCallbackr8r9rr r)rrrrrtrtrudataLineReceivedsL          zSMTP.dataLineReceivedcCszd}|D]\}}|s|d7}t|q|r5d}t|}|dkr+|d|d|d7}|dt|dS|dd dS) NrrKzCould not send e-mailz (z failures out of z recipients)r0rsDelivery in progress)r*r rrr.)r resultListfailuressuccessresultr resultLenrtrtrurFs  zSMTP._messageHandledcCsZ|\}}}t|tr||_d|_nt|trd|_||_nt|jd||_d|_dS)zR Save the state resulting from a successful anonymous cred login. Nz is not a supported interface) issubclassr&rrr% RuntimeErrorrrA challenger)rrMifaceavatarlogoutrtrtru_cbAnonymousAuthentications    zSMTP._cbAnonymousAuthenticationcsjdur j_jdurtjjSjrDjtj dt t }fdd}| j|fdd}|||St)a Validate the address from which the message originates. @type helo: C{(bytes, bytes)} @param helo: The argument to the HELO command and the client's IP address. @type origin: C{Address} @param origin: The address the message is from @rtype: C{Deferred} or C{Address} @return: C{origin} or a C{Deferred} whose callback will be passed C{origin}. @raise SMTPBadSender: Raised of messages from this address are not to be accepted. NcsB|tjjr t}n|tjjrtdd}n|St|S)z Translate cred exceptions into SMTP exceptions so that the protocol code which invokes C{validateFrom} can properly report the failure. z#Unauthenticated senders not allowed)r)rrr UnauthorizedLoginrUnhandledCredentialsrfail)r exc)r;rtruebAuthenticationEs  z+SMTP.validateFrom..ebAuthenticationcs S)zE Re-attempt from address validation. )r)ignoredrr;rrtrucontinueValidationWs z-SMTP.validateFrom..continueValidation)rgetMessageDeliveryrrrrportalloginr credentials Anonymousr&r%rrUrHr)rrr;rMrZr]rtr\rur!s"     zSMTP.validateFromcCs|jdur |j|St|)a Validate the address for which the message is destined. @type user: L{User} @param user: The address to validate. @rtype: no-argument callable @return: A C{Deferred} which becomes, or a callable which takes no arguments and returns an object implementing C{IMessage}. This will be called and the returned object used to deliver the message when it arrives. @raise SMTPBadRcpt: Raised if messages to the address are not to be accepted. N)rr%rrr(rtrtrur%bs  zSMTP.validateToc Cs|jdur |j|||Sd}|drd|d}t|jj}d|dd|dd|d}d ||jjtf}d d t t |t f}d |d |d |S)Nrrs helo=sfrom s ([rK])sby %s with %s (%s)s for %s; %s s Received: s ) rr7r.rgetHostrrrrrmaprrC) rrr;r<heloStrrfrom_byfor_rtrtrur7vs  $zSMTP.receivedHeaderr)r)rr)Nrr+)3rrrrrr_r:rrrArpropertyrsetterrrrrrrrrrrrrrqstringrrIrr r$rrrr*r&r'r/r@rrCrI state_DATArFrUrr%r7rtrtrtrur;s            (*A r;c@s2eZdZdZeZdZeZdZ dddZ ddZ dS) r=z Factory for SMTP. rNcC ||_dSrw)r_)rr_rtrtrurrzSMTPFactory.__init__cCs"tj||}|j|_|j|_|Srw)r ServerFactory buildProtocolr_rrrrprtrtrurtszSMTPFactory.buildProtocolrw) rrrrrrrr;r r_rrtrtrtrtrur=s  r=c@seZdZdZdZdZd3ddZddZd d Ze j fd d Z d dZ ddZ ddZddZddZddZddZddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2ZdS)4r<a SMTP client for sending emails. After the client has connected to the SMTP server, it repeatedly calls L{SMTPClient.getMailFrom}, L{SMTPClient.getMailTo} and L{SMTPClient.getMailData} and uses this information to send an email. It then calls L{SMTPClient.getMailFrom} again; if it returns L{None}, the client will disconnect, otherwise it will continue as normal i.e. call L{SMTPClient.getMailTo} and L{SMTPClient.getMailData} and send a new email. TN cCsLt|tr |d}|p d|_g|_g|_d|_g|_d|_t ||_ dS)NrIrr) rrridentitytoAddressesResultsuccessAddressesrrrr+LineLogr*)rrxlogsizertrtrurs   zSMTPClient.__init__cCs(|jr |jd|tj||dS)Ns>>> )debugr*rr( LineReceiverrrrtrtrurszSMTPClient.sendLinecCs(||jdg|_|j|_|j|_dSr)rr _expectedsmtpState_helo _okresponsesmtpConnectionFailed _failresponserrtrtrurs  zSMTPClient.connectionMadecCs|dd|_dS)z, We are no longer connected N)rmailFilerrBrtrtrurs  zSMTPClient.connectionLostcCs|tdd|jdS)Nrs(Timeout waiting for SMTP server response) sendErrorr!r*rrrtrtrurs  zSMTPClient.timeoutConnectionc Cs||jr|jd|d}z t|dd|_Wnty5|tdd||j YdSw|dddkr@dS|j |dd|ddd krTdS|j|j vrf| |jd |j }n ||jd |j }d|_g|_ |S) Ns<<< rcrz#Invalid response from SMTP server: rrK0rd- )rr}r*rrmr ValueErrorrrrrrrrr)rrwhyrtrtrurs6   zSMTPClient.lineReceivedcCs|t|||jdSrw)rrr*rrrrrtrtrurszSMTPClient.smtpConnectionFailedcCs4|dkr|t|||jdS|||dS)Nr)rrr*rsmtpState_msgSentrrtrtrusmtpTransferFailedszSMTPClient.smtpTransferFailedcCs"|d|jt|_|j|_dS)NsHELO )rrxSUCCESSrsmtpState_fromrrrtrtrur s zSMTPClient.smtpState_helocCsP||_|j|_|jdur"|dt|jdg|_|j|_dS| dS)Ns MAIL FROM:r) getMailFromrrrrrBr smtpState_tor_disconnectFromServerrrtrtrurs    zSMTPClient.smtpState_fromcCs|jdSrw)rrrrtrtrusmtpState_disconnectrzSMTPClient.smtpState_disconnectcCs@t||_g|_g|_|j|_tdd|_d|_ |ddS)Nrr) iter getMailTo toAddressesryrzsmtpState_toOrDatarranger lastAddressrrtrtrurs  zSMTPClient.smtpState_tocCs|jdur|j|j||f|tvr|j|jzt|j|_Wn"tyD|jr<|ddg|_ |j |_ YdS| |dYSw|dt |jdS)NsDATAr1zNo recipients acceptedsRCPT TO:)rryrrrzrxr StopIterationrrsmtpState_datarrrBrrtrtrur%s   zSMTPClient.smtpState_toOrDatacsJt}|jj}fdd}|j|t_ j _ dS)Ncs|jdSrw)rr)r rrtru ebTransfer:rz-SMTPClient.smtpState_data..ebTransfer) r( FileSenderbeginFileTransfer getMailDatartransformChunkrfinishedFileTransferrrrr)rrrsr)rrtrrur6s   zSMTPClient.smtpState_datacCsN|jdur|||t|j|j|jg|_d|_|dt|_|j |_ dS)NsRSET) rsentMailrrzryr*rrrrrrrtrtrurAs   zSMTPClient.smtpState_msgSentcCs||ddddS)a  Perform the necessary local to network newline conversion and escape leading periods. This method also resets the idle timeout so that as long as process is being made sending the message body, the client will not time out. rs  .s ..)rreplace)rchunkrtrtrurPszSMTPClient.transformChunkcCs |dkrd}nd}||dS)Nrrr)r)rlastsentrrtrtrur[szSMTPClient.finishedFileTransfercCt)z< Return the email address the mail is from. NotImplementedErrorrrtrtrurdzSMTPClient.getMailFromcCr)z5 Return a list of emails to send to. rrrtrtrurjrzSMTPClient.getMailTocCr)z Return file-like object containing data of message to be sent. Lines in the file should be delimited by '\n'. rrrtrtrurpszSMTPClient.getMailDatacCs,t|tr|js|dS|dddS)a2 If an error occurs before a mail message is sent sendError will be called. This base class method sends a QUIT if the error is non-fatal and disconnects the connection. @param exc: The SMTPClientError (or child class) raised @type exc: C{SMTPClientError} rN)rrisFatalrrrrYrtrtrurxs zSMTPClient.sendErrorcCr)a Called when an attempt to send an email is completed. If some addresses were accepted, code and resp are the response to the DATA command. If no addresses were accepted, code is -1 and resp is an informative message. @param code: the code returned by the SMTP Server @param resp: The string response returned from the SMTP Server @param numOk: the number of addresses accepted by the remote host. @param addresses: is a list of tuples (address, code, resp) listing the response to each RCPT command. @param log: is the SMTP session log r)rrrnumOk addressesr*rtrtrurszSMTPClient.sentMailcCs"tdd|_|j|_|ddS)NrrsQUIT)rrrrrrrtrtrurs z SMTPClient._disconnectFromServer)rw)rrrrr}rrrrr connectionDonerrrrrrrrrrrrrrrrrrrrrtrtrtrur<s6   *      r<c@seZdZdZdZdZdZdZdZd0ddZ ddZ d d Z d1d d Z d1ddZ d1ddZd1ddZd1ddZd1ddZd1ddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/ZdS)2r8a  A client for sending emails over ESMTP. @ivar heloFallback: Whether or not to fall back to plain SMTP if the C{EHLO} command is not recognised by the server. If L{requireAuthentication} is C{True}, or L{requireTransportSecurity} is C{True} and the connection is not over TLS, this fallback flag will not be honored. @type heloFallback: L{bool} @ivar requireAuthentication: If C{True}, refuse to proceed if authentication cannot be performed. Overrides L{heloFallback}. @type requireAuthentication: L{bool} @ivar requireTransportSecurity: If C{True}, refuse to proceed if the transport cannot be secured. If the transport layer is not already secured via TLS, this will override L{heloFallback}. @type requireAuthentication: L{bool} @ivar context: The context factory to use for STARTTLS, if desired. @type context: L{IOpenSSLClientConnectionCreator} @ivar _tlsMode: Whether or not the connection is over TLS. @type _tlsMode: L{bool} TFNcOs.tj|g|Ri|g|_||_||_dSrw)r<rauthenticatorssecretcontext)rrcontextFactoryargskwrtrtrurs zESMTPClient.__init__cCs2|dkrtjdtdd|jStd|jj|f)NtlsModeStlsMode attribute of twisted.mail.smtp.ESMTPClient is deprecated since Twisted 13.0rVcategory stacklevelz%s instance has no attribute %r)warningswarnDeprecationWarning_tlsModerrr)rnamertrtru __getattr__szESMTPClient.__getattr__cCs0|dkrtjdtdd||_dS||j|<dS)NrrrVr)rrrrr)rrrrtrtru __setattr__s zESMTPClient.__setattr__rcC|tdd|jdS)a Fail because authentication is required, but the server does not support ESMTP, which is required for authentication. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} s,Server does not support ESMTP AuthenticationN)rrr*rrrtrtruesmtpEHLORequireds   zESMTPClient.esmtpEHLORequiredcCsPg}|jD] }||qdd|}|tdd||jdS)a Fail because authentication is required, but the server does not support any schemes we support. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} s[%s]s, rs8Server does not support Client Authentication schemes %sN) rrgetNamerrrrr*r)rrrtmpaauthrtrtruesmtpAUTHRequireds zESMTPClient.esmtpAUTHRequiredcCr)a` Fail because TLS is required and the server does not support it. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} rs:Server does not support secure communication via TLS / SSLN)rr#r*rrrtrtruesmtpTLSRequireds zESMTPClient.esmtpTLSRequiredcCs|t|d|jdS)a[ Fail because the TLS handshake wasn't able to be completed. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} s(Could not complete the SSL/TLS handshakeN)rr0r*rrrtrtruesmtpTLSFailed&s   zESMTPClient.esmtpTLSFailedcC|t|||jdS)aM Fail because the authentication was rejected. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} N)rrr*rrrtrtruesmtpAUTHDeclined8 zESMTPClient.esmtpAUTHDeclinedcCr)ab Fail because the server sent a malformed authentication challenge. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} r sRLogin failed because the SMTP Server returned a malformed Authentication ChallengeNrrr*rrrtrtruesmtpAUTHMalformedChallengeFs z'ESMTPClient.esmtpAUTHMalformedChallengecCr)aP Fail because of some other authentication error. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} NrrrtrtruesmtpAUTHServerError[rz ESMTPClient.esmtpAUTHServerErrorcCs|j|dS)a Registers an Authenticator with the ESMTPClient. The ESMTPClient will attempt to login to the SMTP Server in the order the Authenticators are registered. The most secure Authentication mechanism should be registered first. @param auth: The Authentication mechanism to register @type auth: L{IClientAuthentication} implementor @return: L{None} N)rr)rrrtrtruregisterAuthenticatoris z!ESMTPClient.registerAuthenticatorcCs$t|j|_t||j|_dS)zp Called when a connection has been made, and triggers sending an C{EHLO} to the server. N)r providedByrrr<resmtpState_ehlorrrtrtrurws  zESMTPClient.connectionMadecCsTt|_|j|_|j|_|jrd}n|j}|jr |j s |s |j |_| d|j dS)a Send an C{EHLO} to the server. If L{heloFallback} is C{True}, and there is no requirement for TLS or authentication, the client will fall back to basic SMTP. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} @return: L{None} FsEHLO N) rresmtpState_serverConfigrrrrrequireTransportSecurity heloFallbackrequireAuthenticationrrrx)rrrneedTLSrtrtrurszESMTPClient.esmtpState_ehlocCsZi}|D]}|dd}t|dkr|d||d<qd||d<q||||dS)z Handle a positive response to the I{EHLO} command by parsing the capabilities in the server's response and then taking the most appropriate next step towards entering a mail transaction. NrKr)rrrtryTLS)rrritemsrrrtrtrurs   z#ESMTPClient.esmtpState_serverConfigcCsn|j}|jo d|v}|j}|s|s|s||||dS|r1dg|_|j|_|j|_| ddS| dS)a Take a necessary step towards being able to begin a mail transaction. The step may be to ask the server to being a TLS session. If TLS is already in use or not necessary and not available then the step may be to authenticate with the server. If TLS is necessary and not available, fail the mail transmission attempt. This is an internal helper method. @param code: The server status code from the most recently received server message. @type code: L{int} @param resp: The server status response from the most recently received server message. @type resp: L{bytes} @param items: A mapping of ESMTP extensions offered by the server. Keys are extension identifiers and values are the associated values. @type items: L{dict} mapping L{bytes} to L{bytes} @return: L{None} STARTTLSrN) rrr authenticateresmtpState_starttlsrrrrr)rrrrhasTLScanTLSmustTLSrtrtrurs%  zESMTPClient.tryTLScCsNz |j|jd|_Wntyt|dYnw|||dS)z Handle a positive response to the I{STARTTLS} command by starting a new TLS session on C{self.transport}. Upon success, re-handshake with the server to discover what capabilities it has when TLS is in use. TrN) rstartTLSrrr-r*r rrrrtrtrurs  zESMTPClient.esmtpState_starttlsc Cs|jrk|drk|d}i}|D]}d||<q|jD]L}|}||vrj||_|dkrT|j|_|j |_ dg|_ t |j|jd} |d|| fdSdg|_ |j|_|j|_ |d|dSq|jrt|dS|||dS)NAUTHrKPLAINs AUTH %s %sNsAUTH )rgetrrrr _authinforr_esmtpState_plainAuthrrbase64 b64encodechallengeResponseresmtpState_challengerrr) rrrrschemes tmpSchemesrrr challengertrtrurs6     zESMTPClient.authenticatecCs@|j|_|j|_dg|_t|j|j d}| d|dS)NrrVs AUTH PLAIN ) rrrrrrrrrrr)rrrrrtrtrurs z!ESMTPClient._esmtpState_plainAuthcCs||j|dSrw) _authResponserrrtrtrur$sz ESMTPClient.esmtpState_challengecCs||j|_zt|}Wntjy#|d|j|_|j|_YdSw| |j |}ddg|_ |j |_|t |dS)N*rr)rrr b64decodebinasciiErrorrrrrrrsmtpState_maybeAuthenticatedr)rrrrrtrtrur's  zESMTPClient._authResponsecCs.|dkr|`|||dS||j|dS)z Called to handle the next message from the server after sending a response to a SASL challenge. The server response might be another challenge or it might indicate authentication has succeeded. rN)rrrrrtrtrur6sz(ESMTPClient.smtpState_maybeAuthenticatedrw)rN)rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrtrtrtrur8s8         3' r8c@s~eZdZdZdZdZdZdddZddZddZ d d Z d d Z d dZ ddZ ddZddZddZddZddZdS)r7NFcCs,t||dur i}||_d|_||_dS)NF)r;r challengers authenticatedctx)rchalrrtrtrurLs  zESMTP.__init__cCs.t|t|j|_|jo|jdu|_dSrw)r;rrrr canStartTLSrrrtrtrurTs zESMTP.connectionMadecCst|dS)Ns ESMTP)r;rrrtrtrurYrzESMTP.greetingcCs*dt|ji}|jr|jsd|d<|S)z SMTP service extensions @return: the SMTP service extensions that are supported. @rtype: L{dict} with L{bytes} keys and a value of either L{None} or a L{list} of L{bytes}. rNr)rrkeysr startedTLS)rextrtrtru extensions\s zESMTP.extensionscCs4t|}t||}|durt|d|d}|S)Next_)r-r;rrr)rrrrtrtruris  zESMTP.lookupMethodcCsTg}|D]\}}|dur|r||dd|q||qd|S)N r)rrrr)rrcvrtrtrulistExtensionsqs  zESMTP.listExtensionscCs\|jj}t|ts|d}||f|_d|_g|_| d|jd|d| dS)Nrrrs, nice to meet you ) rrrrrrrrrrr)rrrrtrtrudo_EHLO}s$    z ESMTP.do_EHLOcCsV|jr |dddS|jr#|jr#|dd|j|jd|_dS|dddS)NrsTLS already negotiatedrsBegin TLS negotiation nowTsTLS not available)rrrrrrrrtrtru ext_STARTTLSs   zESMTP.ext_STARTTLScCs|jr |dddS|dd}|j|ddd}|s)|dddSt|_||_t |dkr>| |d}nd}| |dS) NrsAlready authenticatedrKrcSsdSrwrtrtrtrtrurzsz ESMTP.ext_AUTH..is Unrecognized authentication type) rrrrrrrrrQr getChallenge state_AUTH)rrrrrtrtruext_AUTHs     zESMTP.ext_AUTHcCst||}d|_|S)zz Save the state resulting from a successful cred login and mark this connection as authenticated. T)r;rUr)r loginInforMrtrtru_cbAuthenticateds zESMTP._cbAuthenticatedcCs@d|_|tjjr|dddSt|d|dddS)a Handle cred login errors by translating them to the SMTP authenticate failed. Translate all other errors into a generic SMTP error code and log the failure for inspection. Stop all errors from propagating. @param reason: Reason for failure. NisAuthentication failedzSMTP authentication failurerr)rrrr rVrr*r rrtrtru_ebAuthenticateds  zESMTP._ebAuthenticatedc s4jdurddt_dS|dur&j}t|}d|dS|dkr8ddd_t_dSzt|}Wnt t j fyXddd_t_YdSwj |j rvj}t|}d|dSt_jjdtt}|j|fd d |jdS) a+ Handle one step of challenge/response authentication. @param response: The text of a response. If None, this function has been called as a result of an AUTH command with no initial response. A response of '*' aborts authentication, as per RFC 2554. Nr s Temporary authentication failurerrr sAuthentication aborteds'Syntax error in parameters or argumentscs ddS)NrsAuthentication successful.r)ignrrtrurzs z"ESMTP.state_AUTH..)r_rrrrQr rrr TypeErrorrr setResponsemoreChallengesr`r&r%rHr addErrbackr)rresponserencodeduncodedcodedrMrtrrur sJ              zESMTP.state_AUTHr)rrrrrrrrrrrrrr r rrrr rtrtrtrur7Es"     r7c@s<eZdZdZdZddZddZddZd d Zd d Z d S)r6zi Utility class for sending emails easily. Use with SMTPSenderFactory or ESMTPSenderFactory. rcCs|js d|_t|jjSdSNrK)donerfactoryrrrtrtrurs zSenderMixin.getMailFromcC|jjSrw)rtoEmailrrtrtrur zSenderMixin.getMailTocCrrw)rfilerrtrtrurr zSenderMixin.getMailDatacCsTt|||jjdks|js&|jdkr|jdks(d|j_|jj|dSdSdS)NrirT) r<rrretriesretryr sendFinishedrMerrbackrrtrtrurs  zSenderMixin.sendErrorc Csd|j_|tvrBg}|D]\}}} |tvr'||dtd|fd| q ||t||d||} |jj | dS|jj ||fdS)NTrz%03drr) rr$rrr.rrrrMr%callback) rrrrrr*errlogracodearesprYrtrtrur!szSenderMixin.sentMailN) rrrrrrrrrrrtrtrtrur6s r6c@seZdZdZdS)r>z| SMTP protocol that sends a single email based on information it gets from its factory, a L{SMTPSenderFactory}. N)rrrrrtrtrtrur>4sr>c@s`eZdZUdZeZeZee e d<dddZ ddZ d d Z d d Zd dZddZddZdS)r?a Utility factory for sending emails easily. @type currentProtocol: L{SMTPSender} @ivar currentProtocol: The current running protocol returned by L{buildProtocol}. @type sendFinished: C{bool} @ivar sendFinished: When the value is set to True, it means the message has been sent or there has been an unrecoverable error or the sending has been cancelled. The default value is False. r reNc Cst|tsJt|tr|dg}n!t|tr|g}ng}|D]}t|ts,|d}||q |}t||_t||_ ||_ ||_ ||_ |j |jd|_d|_| |_||_dS)ao @param fromEmail: The RFC 2821 address from which to send this message. @param toEmail: A sequence of RFC 2821 addresses to which to send this message. @param file: A file-like object containing the message to send. @param deferred: A Deferred to callback or errback when sending of this message completes. @type deferred: L{defer.Deferred} @param retries: The number of times to retry delivery of this message. @param timeout: Period, in seconds, for which to wait for server responses, or None to wait forever. rIFN)rrmrrrrr3rrnEmailsrr!rMaddBoth_removeDeferredr$currentProtocolr"r) rrrr!deferredr"r toEmailFinal_emailrtrtrurLs*        zSMTPSenderFactory.__init__cCs|`|Srw)rMrrMrtrtrur,{sz!SMTPSenderFactory._removeDeferredcC|||dSrw_processConnectionErrorr connectorr rtrtruclientConnectionFailedrz(SMTPSenderFactory.clientConnectionFailedcCr2rwr3r5rtrtruclientConnectionLostrz&SMTPSenderFactory.clientConnectionLostcCsd|_|jdkr(|js(td|j |jdd||jd7_dS|js@|t j r7t dd|_ |j |j dSdS)Nrz&SMTP Client retrying server. Retry: %srKrzUnable to connect to server.)r-r"r$r*rr!seekconnectrr ConnectionDonerrrMr%r5rtrtrur4s  z)SMTPSenderFactory._processConnectionErrorcCs>||j|jdd}||_|j|_||_|j|j|S)NrV) r rr*rrr-rMr+_removeProtocolrurtrtrurts zSMTPSenderFactory.buildProtocolcCs|jrd|_|S)z Remove the protocol created in C{buildProtocol}. @param result: The result/error passed to the callback/errback of L{defer.Deferred}. @return: The C{result} untouched. N)r-r1rtrtrur<s z!SMTPSenderFactory._removeProtocol)reN)rrrrrrr>r rr<__annotations__rr,r7r8r4rtr<rtrtrtrur?;s   / r?c@seZdZdZddZdS)ra& L{LOGINCredentials} generates challenges for I{LOGIN} authentication. For interoperability with Outlook, the challenge generated does not exactly match the one defined in the U{draft specification}. cCst|ddg|_dS)Ns Password:s Username:) _lcredentialsr challengesrrtrtrurs zLOGINCredentials.__init__N)rrrrrrtrtrtrurs rc@s&eZdZddZddZd ddZdS) r2cCrrrwr(rcrtrtrurrzPLAINAuthenticator.__init__cCsdS)NrrtrrtrtrurszPLAINAuthenticator.getNamerKcCs2|dkr|jd|jd|Sd|jd|S)NrKr@)rrrrtrtrursz$PLAINAuthenticator.challengeResponseN)rK)rrrrrrrtrtrtrur2sr2c@s.eZdZdZdZd ddZddZddZdS) r9TNcOsRd|_||_|dd|_|dur|}tj|||g|Ri||dS)Nrhostname)rusernamepop _hostname_getContextFactoryr8r_registerAuthenticators)rrCrrrrrtrtrurs zESMTPSender.__init__cCs4|t|j|t|j|t|jdSrw)rrrCrr2rrtrtrurGsz#ESMTPSender._registerAuthenticatorscCsR|jdur|jS|jdurdSzddlm}Wn ty!YdSw||j}|S)Nr)optionsForClientTLS)rrEtwisted.internet.sslrH ImportError)rrHrrtrtrurFs    zESMTPSender._getContextFactoryrw)rrrrrrrGrFrtrtrtrur9s   r9c@s4eZdZdZeZ       d ddZdd ZdS) r:z Utility factory for sending emails easily. @type currentProtocol: L{ESMTPSender} @ivar currentProtocol: The current running protocol as made by L{buildProtocol}. reNFTc CsDt|||||||||_||_| |_| |_| |_| |_| |_dSrw) r?rrCpassword_contextFactory _heloFallback_requireAuthentication_requireTransportSecurityrE)rrCrKrrr!r.r"rrrrrrBrtrtrurs zESMTPSenderFactory.__init__cCsh|j|j|j|j|j|jdd|jd}|j|_|j |_ |j |_ ||_ |j|_||_|j|j|S)a) Build an L{ESMTPSender} protocol configured with C{heloFallback}, C{requireAuthentication}, and C{requireTransportSecurity} as specified in L{__init__}. This sets L{currentProtocol} on the factory, as well as returning it. @rtype: L{ESMTPSender} rV)rB)r rCrKrLrr*rErMrrNrrOrrrr-rMr+r<rurtrtrurts   z ESMTPSenderFactory.buildProtocol)reNNFTTN)rrrrr9r rrtrtrtrtrur:s  r:Fc  st|ds tt|}fdd} t| } t|tr!|d}t|tr+|d}|} t| ts6t| } t |||||| d| | | d |durMt |_ | ||| S)aR Send an email. This interface is intended to be a replacement for L{smtplib.SMTP.sendmail} and related methods. To maintain backwards compatibility, it will fall back to plain SMTP, if ESMTP support is not available. If ESMTP support is available, it will attempt to provide encryption via STARTTLS and authentication if a secret is provided. @param smtphost: The host the message should be sent to. @type smtphost: L{bytes} @param from_addr: The (envelope) address sending this mail. @type from_addr: L{bytes} @param to_addrs: A list of addresses to send this mail to. A string will be treated as a list of one address. @type to_addrs: L{list} of L{bytes} or L{bytes} @param msg: The message, including headers, either as a file or a string. File-like objects need to support read() and close(). Lines must be delimited by '\n'. If you pass something that doesn't look like a file, we try to convert it to a string (so you should be able to pass an L{email.message} directly, but doing the conversion with L{email.generator} manually will give you more control over the process). @param senderDomainName: Name by which to identify. If None, try to pick something sane (but this depends on external configuration and may not succeed). @type senderDomainName: L{bytes} @param port: Remote port to which to connect. @type port: L{int} @param username: The username to use, if wanting to authenticate. @type username: L{bytes} or L{unicode} @param password: The secret to use, if wanting to authenticate. If you do not specify this, SMTP authentication will not occur. @type password: L{bytes} or L{unicode} @param requireTransportSecurity: Whether or not STARTTLS is required. @type requireTransportSecurity: L{bool} @param requireAuthentication: Whether or not authentication is required. @type requireAuthentication: L{bool} @param reactor: The L{reactor} used to make the TCP connection. @rtype: L{Deferred} @returns: A cancellable L{Deferred}, its callback will be called if a message is sent to ANY address, the errback if no message is sent. When the C{cancel} method is called, it will stop retrying and disconnect the connection immediately. The callback will be called with a tuple (numOk, addresses) where numOk is the number of successful recipient addresses and addresses is a list of tuples (address, code, resp) giving the response to the RCPT command for each address. readcs(d_jrjjdSdS)z Cancel the L{twisted.mail.smtp.sendmail} call, tell the factory not to retry and disconnect the connection. @param d: The L{defer.Deferred} to be cancelled. TN)r$r-rabortConnection disconnect)r)r6rrtrucancels zsendmail..cancelzutf-8T)rrrrBN) hasattrrrrDeferredrrrr r:r.r connectTCP)smtphost from_addrto_addrsrsenderDomainNameportr rCrKrrrUr) tlsHostnamertrTrur52s6 I        r5cCstg}t|D]*}t|}|dks|dks|dks|dkr(|td|dq|t|fqd|t|fS)N+=!~02Xr)r,ordrr.rrr)rerrorsrchortrtrurHs  rHc Csg}d}|t|kr`|||ddkrFz|ttt||d|ddWnty@|t|||dYnw|d7}n|t|||dd|d7}|t|ks d|t|fS)z Decode the xtext-encoded string C{s}. @param s: String to decode. @param errors: codec error handling scheme. @return: The decoded string. rrK+rcrIr{) rrchrrmrrrdrr)rrerrvrtrtrurGs ,     rGc@eZdZdddZdS)rDstrictcCt|Srw)rGrrrertrtrurr zxtextStreamReader.decodeNrlrrrrrtrtrtrurDrDc@rk)rErlcCrmrw)rHrnrtrtrurr zxtextStreamWriter.decodeNrorprtrtrtrurErqrEcCs|dkr ttttfSdS)Nxtext)rHrGrDrE)rrtrtrurFs rFrrw)yrrrr~rrsocketrfr email.utilsriortypingrzope.interfacertwistedrtwisted.copyrightrtwisted.internetrr r r twisted.internet._idnar twisted.internet.interfacesr rtwisted.mail._credrrrr>twisted.mail._exceptrrrrrrrrrrrrrrr r!r"r0r#twisted.mail.interfacesr$r%r&r'r1twisted.protocolsr(r)twisted.pythonr*r+twisted.python.compatr,r-r.twisted.python.runtimer/__all__isMacOSX gethostnamerrgetfqdndictfromkeysrrrCr@ryrArBrrrrr3r4LineOnlyReceiver TimeoutMixinr;rsr=r~r<r8r7r6r> ClientFactoryr?r2r9r:r5codecsrHrG StreamReaderrD StreamWriterrErFregisterrtrtrtrus       P 6 < s(r)88q&H {