为什么mxrecord应该更改为字符串?

时间:2018-01-03 04:50:32

标签: python python-3.x smtp mx-record

我试图将SMTP服务器连接到域名

import socket()
import smtplib
import dns.resolver

getdomain = user_email.split('@')

            check_domain = dns.resolver.query(getdomain[1], 'MX')
            mxrecords=check_domain[0].exchange

            host=socket.gethostname()
            server=SMTP()
            server.connect(mxrecords)

这会引发我的错误

if not port and (host.find(':') == host.rfind(':')):
AttributeError: 'Name' object has no attribute 'find'

但是当我将mxrecords更改为字符串时,它可以正常工作

mxrecords=str(check_domain[0].exchange)

任何人都可以解释为什么它接受字符串吗?

2 个答案:

答案 0 :(得分:2)

来自https://docs.python.org/3/library/smtplib.html

您可以知道connect()需要字符串参数host

  

SMTP实例封装了SMTP连接。它具有支持完整的SMTP和ESMTP操作的方法。如果给出了可选的主机和端口参数,则在初始化期间使用这些参数调用SMTP connect()方法。

connect()可以点击然后重定向到链接,然后您可以看到:

  

SMTP.connect(host =' localhost',port = 0)
  连接到给定端口上的主机。默认设置是连接到标准SMTP端口(25)的本地主机。如果主机名以冒号(':')结尾,后跟一个数字,则该后缀将被删除,并且该数字将被解释为要使用的端口号。如果在实例化期间指定了主机,则构造函数会自动调用此方法。返回服务器在其连接响应中发送的响应代码和消息的2元组。

在那里你可以知道param host='localhost'默认是一个字符串。

修改

我检查了你的代码,

print(type(mxrecords)) 

打印

<class 'dns.name.Name'>

表示mxrecords对象是dns.name.Name对象,而不是字符串。

如果您点击connect方法的源代码,您会发现host应为字符串:

def connect(self, host='localhost', port=0, source_address=None):
    """Connect to a host on a given port.

    If the hostname ends with a colon (`:') followed by a number, and
    there is no port specified, that suffix will be stripped off and the
    number interpreted as the port number to use.

    Note: This method is automatically invoked by __init__, if a host is
    specified during instantiation.

    """

    if source_address:
        self.source_address = source_address

    if not port and (host.find(':') == host.rfind(':')):
        i = host.rfind(':')
        if i >= 0:
            host, port = host[:i], host[i + 1:]
            try:
                port = int(port)
            except ValueError:
                raise OSError("nonnumeric port")
    if not port:
        port = self.default_port
    if self.debuglevel > 0:
        self._print_debug('connect:', (host, port))
    self.sock = self._get_socket(host, port, self.timeout)
    self.file = None
    (code, msg) = self.getreply()
    if self.debuglevel > 0:
        self._print_debug('connect:', repr(msg))
    return (code, msg)

在代码中,您可以找到与您的错误匹配的host.find(':') == host.rfind(':')

检查dns.name.Name源代码,您会发现Name类有to_text方法:

def to_text(self, omit_final_dot=False):
    """Convert name to text format.
    @param omit_final_dot: If True, don't emit the final dot (denoting the
    root label) for absolute names.  The default is False.
    @rtype: string
    """

    if len(self.labels) == 0:
        return maybe_decode(b'@')
    if len(self.labels) == 1 and self.labels[0] == b'':
        return maybe_decode(b'.')
    if omit_final_dot and self.is_absolute():
        l = self.labels[:-1]
    else:
        l = self.labels
    s = b'.'.join(map(_escapify, l))
    return maybe_decode(s)

因此,您应该使用mxrecords.to_text()来获取MX服务器名称。

答案 1 :(得分:1)

第三方dns.resolver包返回的对象不是标准库smtplib知道任何内容的类型(或类,如果有帮助)。

很多时候,当连接库API时,作为程序员的任务是从一个API作为输出返回的自定义表示转换为适合作为另一个API调用的输入的不同表示。

系统库需要特别注意这一点。如果smtplib(或甚至socket)了解您的特定解析器,则与其他解析器一起使用会更加困难。即使你的解析器也是Python标准库的一部分,这样的内部依赖会引入不受欢迎的僵化,内部耦合,以及可能的一些讨厌的内部版本问题。