将图像作为头像存储到数据存储中:可能吗?
有没有人处理过收到邮件中的附件?我在想,用户可以把图片作为附件发送,而不是自己上传,这样我就可以用这个附件上传到数据存储中。
文档中有关于发送附件的内容,但我找不到关于接收附件的文档。这一页说:
附件
消息的文件附件,以一个包含两个值的元组列表表示,每个附件对应一个元组。
每个元组的第一个元素是文件名,第二个元素是文件内容。
附件文件必须是允许的文件类型之一,文件名必须以与类型对应的扩展名结尾。有关允许的类型和文件扩展名的列表,请参见概述:附件。
我觉得这也和发送邮件有关。
我有这段代码可以把图片保存到数据存储中:
class AvatarSave(webapp.RequestHandler):
def post(self):
q = User.all()
q.filter("userEmail =", emailAddress)
qTable = q.fetch(10)
if qTable:
for row in qTable:
avatar = images.resize(self.request.get("img"), 50, 50)
row.avatar = db.Blob(avatar)
db.put(qTable)
else:
self.response.out.write("user not found")
self.redirect('/')
直观上看,似乎用message.attachment
而不是"img"
就可以解决问题。
avatar = images.resize(self.request.get(message.attachment), 50, 50)
你觉得怎么样?谢谢。
更新2(根据Nick Johnson的评论更新的新代码)
class Register(InboundMailHandler):
def receive(self, message):
senderEmail = message.sender
emailTuple = parseaddr(senderEmail)
emailUserName = emailTuple[0]
emailAddress = emailTuple[1]
newAvatar = db.Blob(images.resize(goodDecode(message.attachments[0][1]), 50, 50))
newUser = User(userEmail=emailAddress,
userName=emailUserName,
avatar=newAvatar)
db.put(newUser)
更新1 问题解决了:
为了记录下来,也为了有同样问题的人请注意,消息的属性是attachments
而不是attachment
:
message.attachment
会出现AttributeError
错误
AttributeError: 'InboundEmailMessage' object has no attribute 'attachment'
而对象message.attachment
看起来是这样的:
[('portrait.png', <EncodedPayload payload=#8461006914571150170 encoding=base64>)]
所以提取<EncodedPayload payload=#8461006914571150170 encoding=base64>
部分的正确方法是
avatar = images.resize(goodDecode(message.attachments[0][1]), 50, 50)
我之前发布的原始代码是
avatar = images.resize(goodDecode(message.attachments[1]), 50, 50)
显然这不管用。
再次感谢jesmith
和Robert Kluin
的回答。
更新0(关于jesmith
的回答)
在我的情况下,我从用户上传的表单中获取一张图片"img"
,并像这样写入数据存储:
for row in qTable:
avatar = images.resize(self.request.get("img"), 50, 50)
row.avatar = db.Blob(avatar)
db.put(qTable)
self.redirect('/')
else:
logging.info("else user not found")
self.redirect('/user-not-found')
在你的代码中,这对应于这一部分,我相信:
try:
if hasattr(message, "attachment"):
for a in message.attachments:
msg.attachmentNames.append(a[0])
msg.attachmentContents.append(append(db.Blob(goodDecode(a[1])))
msg.put()
except:
logging.exception("exception decoding attachments in email from %s" % message.sender)
假设在我的情况下只有一个附件;我该如何获取附件的数据部分?
是message.attachment[1]
吗?
avatar = images.resize(message.attachment[1], 50, 50)
是message.attachment[1]
附件的数据部分吗?
谢谢!
3 个回答
查看一下处理接收邮件这一部分的文档,它解释了附件的属性。
InboundEmailMessage对象包含了一些属性,可以用来访问其他邮件字段:
- attachments是一个文件附件的列表,可能是空的。列表中的每个值都是一个包含两个元素的元组:文件名和文件内容。
所以你需要的东西大概是这样的:
for file_name, data in message.attachments:
# add some tests to check that the
# file-type is correct and that the
# data-size is "OK".
avatar = db.Blob(data)
你需要决定当用户附加了多个图片时该如何处理。这段代码会简单地使用最后一个附件。
是的,关于你的后续问题:
是 message.attachment[1] 吗?
没错,但你需要对它进行解码。否则,你得到的只是一大堆看起来像是乱码的ASCII字符(在电子邮件中,附件总是以一种7位、短行、1975年安全格式编码,比如base64)。
avatar = images.resize(goodDecode(message.attachment[1]), 50, 50)
而且别忘了在周围加上很多try-catch逻辑,因为在GAE中处理邮件的部分很容易出现很多错误。
这是我用来处理来邮件的一个片段:
bodies = message.bodies(content_type='text/html')
allBodies = u"";
for body in bodies:
allBodies = allBodies + u"\n" + unicode(goodDecode(body[1]), errors="ignore")
if not allBodies:
bodies = message.bodies(content_type='text/plain')
for body in bodies:
allBodies = allBodies + u"\n" + unicode(goodDecode(body[1]), errors="ignore")
msg = EmailMessageModel()
...fill in various stuff...
msg.sender = message.sender
msg.date = datetime.datetime.now()
msg.message = allBodies
# Calling put() before dealing with attachments because it seems like that could throw various exceptions
msg.put()
event.email = True
event.put()
event.project.email = True
event.project.put()
# attachments is a list of element pairs containing file names and contents.
try:
if hasattr(message, 'attachments'):
for a in message.attachments:
msg.attachmentNames.append(a[0])
msg.attachmentContents.append(db.Blob(goodDecode(a[1])))
msg.put()
except:
logging.exception("Exception decoding attachments in email from %s" % message.sender)
需要注意的是,goodDecode是我自己写的一个函数,因为底层的GAE解码有个bug(它把所有内容都变成小写,这样会搞乱base64编码的文本):
def goodDecode(encodedPayload):
if not hasattr(encodedPayload, 'encoding'):
return encodedPayload
encoding = encodedPayload.encoding
payload = encodedPayload.payload
if encoding and encoding.lower() != '7bit':
payload = payload.decode(encoding)
return payload
现在可能不再需要这个函数了,因为我相信他们已经修复了那个bug。
在我的情况下,我把附件存入数据库:
class EmailMessageModel(db.Model):
....various stuff...
sender = db.StringProperty()
date = db.DateTimeProperty()
message = db.TextProperty()
attachmentNames = db.StringListProperty()
attachmentContents = db.ListProperty(db.Blob)
当我想要显示这封邮件时,我使用的是:
<h2>{{ e.sender }} {{ e.date|date:"M j, Y f A " }} GMT</h2>
<p>From: {{ e.sender }}<br/>Date: {{ e.date|date:"M j, Y f A" }} GMT ({{ e.date|timesince }} ago)<br/>Subject: {{ e.subject }}</p>
{% if e.attachmentNames %}
<p>Attachments:
{% for a in e.attachmentNames %}
<a href="/admin/attachment?email={{ e.key }}&index={{ forloop.counter0 }}" target="_blank">{{ a }}</a>
{% endfor %}
</p>
{% endif %}
<div style='background-color: white'>{{ e.message }}</div>
附件处理的部分是:
class AttachmentHandler(webapp.RequestHandler):
def get(self):
email = EmailMessageModel.get(self.request.get('email'))
index = self.request.get('index')
if index:
index = int(index)
filename = email.attachmentNames[index]
self.response.headers['Content-Type'] = str(mimetypes.guess_type(filename)[0]) or 'application/octet-stream'
self.response.out.write(email.attachmentContents[index])
(所以,基本上,我是让浏览器自己决定怎么处理这些附件。)
希望这对你有帮助!