【问题标题】:Why do mxrecord should be change to string?为什么 mxrecord 应该改为字符串?
【发布时间】:2018-06-12 18:32:19
【问题描述】:

我正在尝试将 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)

谁能解释一下为什么它接受字符串?

【问题讨论】:

  • 请发布正确的工作代码包括导入语句。
  • 完成...现在解释一下

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


【解决方案1】:

来自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 元组。

在那里你可以知道参数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 服务器名称。

【讨论】:

  • 我已经编辑了 que... mxrecords=check_domain[0].exchange 现在这不是 tuple.. 你能解释一下吗
  • @Awesome print(type(mxrecords)) 打印的是什么?
  • 这个问题被标记为python-3.x,所以链接到 Python 2 库文档是不够的。
  • @Awesome 看到我的编辑。
  • @tripleee 我已经编辑了我的答案,检查一下。对不起我的英语不好。
【解决方案2】:

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

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

系统库需要特别注意这一点。如果smtplib(甚至socket)知道您的特定解析器,那么与其他解析器一起使用会更加困难。即使您的解析器也是 Python 标准库的一部分,这种内部依赖也会引入不受欢迎的僵化、内部耦合,并可能带来一些令人讨厌的内部版本控制问题。

【讨论】:

  • 你能回答我的问题吗?
  • 话虽如此,dns.resolver 作者可以给对象一个str() 表示;但是 MX 记录不能直接转换为单个主机名。它是一个主机列表,每个主机都有一个数字偏好。
  • 我在这里发布的试图回答页面顶部的问题。如果您认为它缺少一些关键的东西,请您详细说明我应该如何改进它?您觉得问题的哪一部分仍未得到解答?
猜你喜欢
  • 1970-01-01
  • 2011-01-17
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
相关资源
最近更新 更多