класс Net::IMAP
Net::IMAP реализует функциональность клиента протокола Internet Message Access Protocol (IMAP). Протокол описан в [IMAP].
IMAP Обзор
Клиент IMAP подключается к серверу и затем выполняет аутентификацию, используя либо authenticate(), либо login(). После аутентификации доступны различные команды. Большинство из них работают с почтовыми ящиками, которые могут быть организованы в иерархическом пространстве имен, и каждый из которых содержит ноль или более сообщений. Реализация на сервере зависит от конкретной реализации; на сервере UNIX часто реализуется как файлы в формате почтового ящика в иерархии каталогов.
Для работы с сообщениями в почтовом ящике клиент должен сначала выбрать этот почтовый ящик, используя либо select(), либо (для чтения только для просмотра) examine(). После успешного выбора почтового ящика клиент переходит в состояние «выбран» и этот почтовый ящик становится «текущим», для которого неявно применяются команды, связанные с элементами почты.
Сообщения имеют два типа идентификаторов: последовательные номера сообщений и UIDs.
Последовательные номера сообщений нумеруют сообщения в почтовом ящике от 1 до количества элементов в почтовом ящике. Если во время сессии приходит новое сообщение, ему присваивается последовательный номер, равный новому размеру почтового ящика. Если сообщения удаляются из почтового ящика, оставшиеся сообщения изменяют свои последовательные номера, «сдвигая» их вниз, чтобы заполнить пробелы.
С другой стороны, UIDs гарантированно не идентифицируют другое сообщение в том же почтовом ящике, даже если существующее сообщение удалено. UIDs должны назначаться в порядке возрастания (но необязательно последовательно) в пределах почтового ящика; это означает, что если клиент, не поддерживающий IMAP, изменяет порядок элементов почты в почтовом ящике, UIDs должны быть переназначены. Клиент IMAP поэтому не может изменять порядок сообщений.
Примеры использования
Вывод отправителя и темы всех последних сообщений в стандартном почтовом ящике
imap = Net::IMAP.new('mail.example.com')
imap.authenticate('LOGIN', 'joe_user', 'joes_password')
imap.examine('INBOX')
imap.search(["RECENT"]).each do |message_id|
envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
puts "#{envelope.from[0].name}: \t#{envelope.subject}"
end
Перемещение всех сообщений из апреля 2003 года из «Mail/sent-mail» в «Mail/sent-apr03»
imap = Net::IMAP.new('mail.example.com')
imap.authenticate('LOGIN', 'joe_user', 'joes_password')
imap.select('Mail/sent-mail')
if not imap.list('Mail/', 'sent-apr03')
imap.create('Mail/sent-apr03')
end
imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id|
imap.copy(message_id, "Mail/sent-apr03")
imap.store(message_id, "+FLAGS", [:Deleted])
end
imap.expunge
Thread Безопасность многопоточности
Net::IMAP поддерживает одновременную работу нескольких потоков. Например,
imap = Net::IMAP.new("imap.foo.net", "imap2")
imap.authenticate("cram-md5", "bar", "password")
imap.select("inbox")
fetch_thread = Thread.start { imap.fetch(1..-1, "UID") }
search_result = imap.search(["BODY", "hello"])
fetch_result = fetch_thread.value
imap.disconnect
Этот скрипт вызывает команды FETCH и SEARCH одновременно.
Ошибки
Сервер IMAP может отправлять три разных типа ответов, чтобы указать на ошибку:
- NO
-
попытка выполнить команду не удалась. Например, имя пользователя/пароль, используемые для входа, неверны; выбранный почтовый ящик не существует и т.д.
- BAD
-
запрос от клиента не соответствует пониманию сервером протокола
IMAP. Это включает попытку команд из неправильного состояния клиента; например, попытка выполнить команду SEARCH без выбора текущего почтового ящика. Также может указывать на внутреннюю ошибку сервера (например, сбой диска). - BYE
-
сервер завершает работу. Это может быть частью обычной последовательности выхода, и может использоваться в процессе входа для указания того, что сервер (по какой-либо причине) не хочет принимать ваше подключение. В ответ на любую другую команду, это указывает либо на то, что сервер выключается, либо на то, что сервер отключает подключение клиента из-за бездействия.
Эти три ответа об ошибках представлены ошибками Net::IMAP::NoResponseError, Net::IMAP::BadResponseError и Net::IMAP::ByeResponseError, которые являются подклассами Net::IMAP::ResponseError. По существу, все методы, которые подразумевают отправку запроса на сервер, могут генерировать одну из этих ошибок. Только наиболее важные случаи описаны ниже.
Поскольку класс IMAP использует сокеты для связи, его методы также подвержены различным ошибкам, которые могут возникнуть при работе с сокетами. Они обычно представлены как ошибки Errno. Например, любой метод, который подразумевает отправку запроса на сервер и/или получение ответа от него, может вызвать ошибку Errno::EPIPE, если сетевое соединение неожиданно прервётся. Обратитесь к руководствам man по сокетам(7), ip(7), tcp(7), socket(2), connect(2) и связанным с ними.
Наконец, Net::IMAP::DataFormatError выбрасывается, если обнаружено, что данные низкого уровня имеют неправильный формат (например, при преобразовании между UTF-8 и UTF-16), и Net::IMAP::ResponseParseError выбрасывается, если ответ сервера не может быть проанализирован.
Ссылки
- [IMAP]
-
-
Crispin, «INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1»,
RFC 2060, декабрь 1996 года. (Примечание: устарел RFC 3501)
-
- [LANGUAGE-TAGS]
-
Alvestrand, H., «Метки для идентификации языков», RFC 1766, март 1995 года.
- [MD5]
-
Myers, J., и M. Rose, «Поле заголовка Content-MD5», RFC 1864, октябрь 1995 года.
- [MIME-IMB]
-
Freed, N., и N. Borenstein, «MIME (Multipurpose Internet Mail Extensions) Часть первая: Формат тел сообщений в Интернете», RFC 2045, ноябрь 1996 года.
- [RFC-822]
-
Crocker, D., «Стандарт для формата текстовых сообщений ARPA Internet», STD 11, RFC 822, Университет Делавэра, август 1982 года.
- [RFC-2087]
-
Myers, J., «Расширение IMAP4 QUOTA», RFC 2087, январь 1997 года.
- [RFC-2086]
-
Myers, J., «Расширение IMAP4
ACL», RFC 2086, январь 1997 года. - [RFC-2195]
-
Klensin, J., Catoe, R., и Krumviede, P., «Расширение IMAP/POP AUTHorize для простого вызова/ответа», RFC 2195, сентябрь 1997 года.
- [SORT-THREAD-EXT]
-
Crispin, M., «INTERNET MESSAGE ACCESS PROTOCOL - Расширения SORT и THREAD», draft-ietf-imapext-sort, май 2003 года.
- [OSSL]
- [RSSL]
- [UTF7]
-
Goldsmith, D. и Davis, M., «UTF-7: Формат преобразования Unicode, безопасный для почты», RFC 2152, май 1997 года.
Константы
- ANSWERED
-
Флаг, указывающий, что сообщение было обработано.
- Address
-
Net::IMAP::Addressпредставляет электронные адреса почты.Поля:
- name
-
Возвращает фразу из [RFC-822] почтового ящика.
- route
-
Возвращает маршрут из [RFC-822] route-addr.
- mailbox
-
nil указывает конец группы [RFC-822]. Если не nil и host — nil, возвращает имя группы [RFC-822]. В противном случае возвращает локальную часть [RFC-822].
- host
-
nil указывает синтаксис группы [RFC-822]. В противном случае возвращает доменное имя [RFC-822].
- ContentDisposition
-
Net::IMAP::ContentDispositionпредставляет поля Content-Disposition.Поля:
- dsp_type
-
Возвращает тип расположения.
- param
-
Возвращает хеш, представляющий параметры поля Content-Disposition.
- ContinuationRequest
-
Net::IMAP::ContinuationRequestпредставляет запросы продолжения команды.Ответ на запрос продолжения команды обозначается маркером “+” вместо тега. Эта форма ответа указывает, что сервер готов принять продолжение команды от клиента. Остальная часть этого ответа — строка текста.
continue_req ::= "+" SPACE (resp_text / base64)
Поля:
- data
-
Возвращает данные (Net::IMAP::ResponseText).
- raw_data
-
Возвращает строку исходных данных.
- DATE_MONTH
- DELETED
-
Флаг, указывающий, что сообщение помечено для удаления. Это произойдёт при закрытии или очистке почтового ящика.
- DRAFT
-
Флаг, указывающий, что сообщение является черновиком или промежуточной версией.
- Envelope
-
Net::IMAP::Envelopeпредставляет структуры конвертов сообщений.Поля:
- date
-
Возвращает строку, представляющую дату.
- subject
-
Возвращает строку, представляющую тему.
- from
-
Возвращает массив
Net::IMAP::Address, представляющий отправителя. - sender
-
Возвращает массив
Net::IMAP::Address, представляющий отправителя. - reply_to
-
Возвращает массив
Net::IMAP::Address, представляющий ответ. - to
-
Возвращает массив
Net::IMAP::Address, представляющий получателей. - cc
-
Возвращает массив
Net::IMAP::Address, представляющий список копий. - bcc
-
Возвращает массив
Net::IMAP::Address, представляющий скрытые копии. - in_reply_to
-
Возвращает строку, представляющую in-reply-to.
- message_id
-
Возвращает строку, представляющую message-id.
- FLAGGED
-
Флаг, указывающий, что сообщение помечено для особого или срочного внимания.
- FetchData
-
Net::IMAP::FetchDataпредставляет содержимое ответа FETCH.Поля:
- seqno
-
Возвращает порядковый номер сообщения. (Примечание: не уникальный идентификатор, даже для ответа команды UID.)
- attr
-
Возвращает хеш. Каждый ключ — имя элемента данных, а каждое значение — его значение.
Текущие элементы данных:
- BODY
-
Форма BODYSTRUCTURE без расширенных данных.
-
Net::IMAP::BodyTypeBasic,Net::IMAP::BodyTypeText,Net::IMAP::BodyTypeMessage,Net::IMAP::BodyTypeMultipart.
- ENVELOPE
-
Объект
Net::IMAP::Envelope, описывающий структуру конверта сообщения. - FLAGS
-
Массив символов флагов, установленных для данного сообщения. Символы флагов капитализируются с помощью
String#capitalize. - INTERNALDATE
-
Строка, представляющая внутреннюю дату сообщения.
- RFC822
-
Эквивалентно BODY[].
- RFC822.HEADER
-
Эквивалентно BODY.PEEK.
- RFC822.SIZE
-
Число, выражающее размер сообщения [RFC-822].
- RFC822.TEXT
-
Эквивалентно BODY.
- UID
-
Число, выражающее уникальный идентификатор сообщения.
Флаг, указывающий, что почтовый ящик был помечен сервером как «интересный»; это обычно означает, что почтовый ящик содержит новые сообщения.
Net::IMAP::MailboxACLItem представляет ответ от GETACL.
acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE rights) identifier ::= astring rights ::= astring
Поля:
- user
-
Имя пользователя, имеющее определенные права доступа к почтовому ящику, указанному в команде getacl.
- rights
-
Права доступа указанного пользователя к почтовому ящику.
Net::IMAP::MailboxList представляет содержимое ответа LIST.
mailbox_list ::= "(" #("\Marked" / "\Noinferiors" /
"\Noselect" / "\Unmarked" / flag_extension) ")"
SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox Поля:
- attr
-
Возвращает атрибуты имени. Каждый атрибут имени — символ, приведенный к верхнему регистру с помощью
String#capitalize, например :Noselect (а не :NoSelect). - delim
-
Возвращает разделитель иерархии.
- name
-
Возвращает имя почтового ящика.
Net::IMAP::MailboxQuota представляет содержимое ответа GETQUOTA. Этот объект также может быть ответом на GETQUOTAROOT. В синтаксическом определении ниже разделитель, используемый в конструкции «#», — одиночное пробельное пространство (SPACE).
quota_list ::= "(" #quota_resource ")"
quota_resource ::= atom SPACE number SPACE number
quota_response ::= "QUOTA" SPACE astring SPACE quota_list Поля:
- mailbox
-
Почтовый ящик с соответствующим квотой.
- usage
-
Текущее использование памяти почтового ящика.
- quota
-
Предел квоты, установленный для почтового ящика.
Net::IMAP::MailboxQuotaRoot представляет часть ответа GETQUOTAROOT. (GETQUOTAROOT также может возвращать Net::IMAP::MailboxQuota.)
quotaroot_response ::= "QUOTAROOT" SPACE astring *(SPACE astring)
Поля:
- mailbox
-
Почтовый ящик с соответствующим квотой.
- quotaroots
-
Ноль или более quotaroots, которые влияют на квоту указанного почтового ящика.
Флаг, указывающий, что имя контекста почтового ящика не может содержать дочерние элементы.
Флаг, указывающий, что почтовый ящик не выбран.
Флаг, указывающий, что сообщение «недавнее», то есть в этом сеансе клиент впервые уведомлен об этом сообщении.
Net::IMAP::ResponseCode представляет коды ответов.
resp_text_code ::= "ALERT" / "PARSE" /
"PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
"READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
"UIDVALIDITY" SPACE nz_number /
"UNSEEN" SPACE nz_number /
atom [SPACE 1*<any TEXT_CHAR except "]">] Поля:
- name
-
Возвращает имя, например «ALERT», «PERMANENTFLAGS» или «UIDVALIDITY».
- data
-
Возвращает данные, если они существуют.
Net::IMAP::ResponseText представляет тексты ответов. Текст может быть префиксным кодом ответа.
resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
;; text SHOULD NOT begin with "[" or "=" Поля:
- code
-
Возвращает код ответа. См. ((<Net::IMAP::ResponseCode>)).
- text
-
Возвращает текст.
Флаг, указывающий, что сообщение просмотрено.
Net::IMAP::StatusData представляет содержимое ответа STATUS.
Поля:
- mailbox
-
Возвращает имя почтового ящика.
- attr
-
Возвращает хеш. Каждый ключ — один из «MESSAGES», «RECENT», «UIDNEXT», «UIDVALIDITY», «UNSEEN». Каждое значение — число.
Net::IMAP::TaggedResponse представляет помеченные ответы.
Ответ сервера о результате завершения операции указывает на успех или неудачу операции. Он помечен тем же тегом, что и команда клиента, которая начала операцию.
response_tagged ::= tag SPACE resp_cond_state CRLF
tag ::= 1*<any ATOM_CHAR except "+">
resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text Поля:
- tag
-
Возвращает тег.
- name
-
Возвращает имя, одно из «OK», «NO» или «BAD».
- data
-
Возвращает данные. См. ((<Net::IMAP::ResponseText>)).
- raw_data
-
Возвращает строку исходных данных.
Net::IMAP::ThreadMember представляет узел потока, возвращаемый Net::IMAP#thread.
Поля:
- seqno
-
Порядковый номер этого сообщения.
- children
-
Массив объектов
Net::IMAP::ThreadMemberдля элементов почтовых сообщений, которые являются дочерними элементами этого в потоке.
Флаг, указывающий, что почтовый ящик не содержит новых сообщений.
Net::IMAP::UntaggedResponse представляет непомеченные ответы.
Data передаются сервером клиенту, а ответы статуса, которые не указывают на завершение команды, имеют префикс «*» и называются непомеченными ответами.
response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
mailbox_data / message_data / capability_data) Поля:
- name
-
Возвращает имя, например «FLAGS», «LIST» или «FETCH».
- data
-
Возвращает данные, такие как массив символов флагов, объект ((<Net::IMAP::MailboxList>)).
- raw_data
-
Возвращает строку исходных данных.
Атрибуты
Поток для обработки исключений.
Возвращает начальное приветственное сообщение от сервера.
Секунды ожидания открытия соединения. Если объект IMAP не может открыть соединение в течение этого времени, он генерирует исключение Net::OpenTimeout. Значение по умолчанию — 30 секунд.
Возвращает все обработчики ответов.
Возвращает записанные немаркированные ответы. Например:
imap.select("inbox")
p imap.responses["EXISTS"][-1]
#=> 2
p imap.responses["UIDVALIDITY"][-1]
#=> 968263756
Методы публичного класса
# File lib/net/imap.rb, line 301 def self.add_authenticator(auth_type, authenticator) @@authenticators[auth_type] = authenticator end
Добавляет аутентификатор для Net::IMAP#authenticate. auth_type — тип аутентификации, поддерживаемый этим аутентификатором (например, “LOGIN”). authenticator — объект, определяющий метод process() для обработки аутентификации с сервером. См. Net::IMAP::LoginAuthenticator, Net::IMAP::CramMD5Authenticator и Net::IMAP::DigestMD5Authenticator для примеров.
Если auth_type относится к существующему аутентификатору, он будет заменён новым.
# File lib/net/imap.rb, line 271 def self.debug return @@debug end
Возвращает режим отладки.
# File lib/net/imap.rb, line 276 def self.debug=(val) return @@debug = val end
Устанавливает режим отладки.
# File lib/net/imap.rb, line 999
def self.decode_utf7(s)
return s.gsub(/&([^-]+)?-/n) {
if $1
($1.tr(",", "/") + "===").unpack1("m").encode(Encoding::UTF_8, Encoding::UTF_16BE)
else
"&"
end
}
end Декодирование строки из модифицированного формата UTF-7 в UTF-8.
UTF-7 — это 7-битовое кодирование Unicode [UTF7]. IMAP использует слегка модифицированную версию для кодирования имён почтовых ящиков, содержащих символы, не входящие в ASCII; см. раздел 5.1.3 [IMAP].
Net::IMAP не кодирует и не декодирует имена почтовых ящиков в UTF-7 автоматически.
# File lib/net/imap.rb, line 306 def self.default_port return PORT end
Порт по умолчанию для подключений IMAP, порт 143
# File lib/net/imap.rb, line 311 def self.default_tls_port return SSL_PORT end
Порт по умолчанию для подключений IMAPS, порт 993
# File lib/net/imap.rb, line 1010
def self.encode_utf7(s)
return s.gsub(/(&)|[^\x20-\x7e]+/) {
if $1
"&-"
else
base64 = [$&.encode(Encoding::UTF_16BE)].pack("m0")
"&" + base64.delete("=").tr("/", ",") + "-"
end
}.force_encoding("ASCII-8BIT")
end Кодирование строки из формата UTF-8 в модифицированный UTF-7.
# File lib/net/imap.rb, line 1022
def self.format_date(time)
return time.strftime('%d-%b-%Y')
end Форматирование time как даты в формате IMAP.
# File lib/net/imap.rb, line 1027
def self.format_datetime(time)
return time.strftime('%d-%b-%Y %H:%M %z')
end Форматирование time как даты и времени в формате IMAP.
# File lib/net/imap.rb, line 281 def self.max_flag_count return @@max_flag_count end
Возвращает максимальное количество флагов, интернированных в символы.
# File lib/net/imap.rb, line 286 def self.max_flag_count=(count) @@max_flag_count = count end
Устанавливает максимальное количество флагов, интернированных в символы.
# File lib/net/imap.rb, line 1070
def initialize(host, port_or_options = {},
usessl = false, certs = nil, verify = true)
super()
@host = host
begin
options = port_or_options.to_hash
rescue NoMethodError
# for backward compatibility
options = {}
options[:port] = port_or_options
if usessl
options[:ssl] = create_ssl_params(certs, verify)
end
end
@port = options[:port] || (options[:ssl] ? SSL_PORT : PORT)
@tag_prefix = "RUBY"
@tagno = 0
@open_timeout = options[:open_timeout] || 30
@parser = ResponseParser.new
@sock = tcp_socket(@host, @port)
begin
if options[:ssl]
start_tls_session(options[:ssl])
@usessl = true
else
@usessl = false
end
@responses = Hash.new([].freeze)
@tagged_responses = {}
@response_handlers = []
@tagged_response_arrival = new_cond
@continued_command_tag = nil
@continuation_request_arrival = new_cond
@continuation_request_exception = nil
@idle_done_cond = nil
@logout_command_tag = nil
@debug_output_bol = true
@exception = nil
@greeting = get_response
if @greeting.nil?
raise Error, "connection closed"
end
if @greeting.name == "BYE"
raise ByeResponseError, @greeting
end
@client_thread = Thread.current
@receiver_thread = Thread.start {
begin
receive_responses
rescue Exception
end
}
@receiver_thread_terminating = false
rescue Exception
@sock.close
raise
end
end Создаёт новый объект Net::IMAP и подключает его к указанному host.
options — хеш-таблица опций, ключи которой — символы.
Доступные опции:
- port
-
Номер порта (значение по умолчанию — 143 для imap или 993 для imaps)
- ssl
-
Если options истинно, будет попытка подключения по SSL (теперь TLS) к серверу. Для этого должны быть установлены расширения
OpenSSL[OSSL] и RubyOpenSSL[RSSL]. Если options — хеш, он передаётся вOpenSSL::SSL::SSLContext#set_paramsв качестве параметров. -
open_timeout -
Секунды ожидания открытия соединения
Наиболее распространённые ошибки:
- Errno::ECONNREFUSED
-
Подключение отклонено сервером или межсетевым экраном.
- Errno::ETIMEDOUT
-
Подключение истекло (возможно, из-за потери пакетов межсетевым экраном).
- Errno::ENETUNREACH
-
Нет маршрута к сети.
-
SocketError -
Хост неизвестен или ошибка сокета.
-
Net::IMAP::ByeResponseError -
Подключение к хосту выполнено успешно, но он сразу же отключился.
MonitorMixin::new Методы публичного экземпляра
# File lib/net/imap.rb, line 906 def add_response_handler(handler = Proc.new) @response_handlers.push(handler) end
Добавляет обработчик ответов. Например, чтобы обнаружить, когда сервер отправляет новый ответ EXISTS (который обычно указывает на добавление новых сообщений в почтовый ящик), добавьте следующий обработчик после выбора почтового ящика:
imap.add_response_handler { |resp|
if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS"
puts "Mailbox now has #{resp.data} messages"
end
}
# File lib/net/imap.rb, line 699
def append(mailbox, message, flags = nil, date_time = nil)
args = []
if flags
args.push(flags)
end
args.push(date_time) if date_time
args.push(Literal.new(message))
send_command("APPEND", mailbox, *args)
end Отправляет команду APPEND для добавления message в конец mailbox. Необязательный параметр flags — массив флагов, изначально передаваемых новому сообщению. Необязательный параметр date_time задаёт время создания нового сообщения; по умолчанию используется текущее время. Например:
imap.append("inbox", <<EOF.gsub(/\n/, "\r\n"), [:Seen], Time.now)
Subject: hello
From: shugo@ruby-lang.org
To: shugo@ruby-lang.org
hello world
EOF
Исключение Net::IMAP::NoResponseError генерируется, если почтовый ящик не существует (он не создаётся автоматически) или если в аргументах flags, date_time или message содержатся ошибки.
# File lib/net/imap.rb, line 417
def authenticate(auth_type, *args)
auth_type = auth_type.upcase
unless @@authenticators.has_key?(auth_type)
raise ArgumentError,
format('unknown auth type - "%s"', auth_type)
end
authenticator = @@authenticators[auth_type].new(*args)
send_command("AUTHENTICATE", auth_type) do |resp|
if resp.instance_of?(ContinuationRequest)
data = authenticator.process(resp.data.text.unpack("m")[0])
s = [data].pack("m0")
send_string_data(s)
put_string(CRLF)
end
end
end Отправляет команду AUTHENTICATE для аутентификации клиента. Параметр auth_type — строка, представляющая используемый механизм аутентификации. В настоящее время Net::IMAP поддерживает следующие механизмы аутентификации:
LOGIN:: login using cleartext user and password.
CRAM-MD5:: login with cleartext user and encrypted password
(see [RFC-2195] for a full description). This
mechanism requires that the server have the user's
password stored in clear-text password. Для обоих механизмов требуется два параметра: имя пользователя и (в открытом виде) пароль. Сервер может не поддерживать один или другой из этих механизмов; проверьте capability() на наличие возможности вида “AUTH=LOGIN” или “AUTH=CRAM-MD5”.
Аутентификация выполняется с помощью соответствующего объекта аутентификатора: см. @@authenticators для получения дополнительной информации о подключении собственного аутентификатора.
Например:
imap.authenticate('LOGIN', user, password)
Исключение Net::IMAP::NoResponseError генерируется, если аутентификация не удалась.
# File lib/net/imap.rb, line 359
def capability
synchronize do
send_command("CAPABILITY")
return @responses.delete("CAPABILITY")[-1]
end
end Отправляет команду CAPABILITY и возвращает массив поддерживаемых сервером возможностей. Каждая возможность — строка. См. [IMAP] для списка возможных возможностей.
Обратите внимание, что класс Net::IMAP не изменяет своего поведения в зависимости от возможностей сервера; пользователю класса необходимо убедиться, что определённая возможность поддерживается сервером перед её использованием.
# File lib/net/imap.rb, line 713
def check
send_command("CHECK")
end Отправляет команду CHECK для запроса контрольной точки текущего выбранного почтового ящика. Это выполняет специфичные для реализации задачи по уходу; например, согласование состояния почтового ящика в памяти и на диске.
# File lib/net/imap.rb, line 720
def close
send_command("CLOSE")
end Отправляет команду CLOSE для закрытия текущего выбранного почтового ящика. Команда CLOSE постоянно удаляет из почтового ящика все сообщения, у которых установлен флаг Удалено.
# File lib/net/imap.rb, line 589
def getquotaroot(mailbox)
synchronize do
send_command("GETQUOTAROOT", mailbox)
result = []
result.concat(@responses.delete("QUOTAROOT"))
result.concat(@responses.delete("QUOTA"))
return result
end
end Отправляет команду GETQUOTAROOT вместе с указанным mailbox. Эта команда, как правило, доступна как администраторам, так и пользователям. Если почтовый ящик существует, возвращает массив, содержащий объекты типа Net::IMAP::MailboxQuotaRoot и Net::IMAP::MailboxQuota.
# File lib/net/imap.rb, line 952
def idle(timeout = nil, &response_handler)
raise LocalJumpError, "no block given" unless response_handler
response = nil
synchronize do
tag = Thread.current[:net_imap_tag] = generate_tag
put_string("#{tag} IDLE#{CRLF}")
begin
add_response_handler(response_handler)
@idle_done_cond = new_cond
@idle_done_cond.wait(timeout)
@idle_done_cond = nil
if @receiver_thread_terminating
raise @exception || Net::IMAP::Error.new("connection closed")
end
ensure
unless @receiver_thread_terminating
remove_response_handler(response_handler)
put_string("DONE#{CRLF}")
response = get_tagged_response(tag, "IDLE")
end
end
end
return response
end Отправляет команду IDLE, которая ожидает уведомлений о новых или удалённых сообщениях. Выводит ответы сервера во время IDLE.
Используйте idle_done(), чтобы выйти из режима IDLE.
Если timeout задано, этот метод возвращает значение после того, как пройдёт timeout секунд. timeout может использоваться для поддержания соединения. Например, следующий код проверяет соединение каждые 60 секунд.
loop do
imap.idle(60) do |res|
...
end
end # File lib/net/imap.rb, line 982
def idle_done
synchronize do
if @idle_done_cond.nil?
raise Net::IMAP::Error, "not during IDLE"
end
@idle_done_cond.signal
end
end Выходит из режима IDLE.
# File lib/net/imap.rb, line 546
def list(refname, mailbox)
synchronize do
send_command("LIST", refname, mailbox)
return @responses.delete("LIST")
end
end Отправляет команду LIST и возвращает подмножество имён из полного набора всех имён, доступных клиенту. refname предоставляет контекст (например, базовый каталог в иерархии почтовых ящиков на основе каталогов). mailbox указывает почтовый ящик или (с помощью подстановочных символов) почтовые ящики в этом контексте. В mailbox могут использоваться два подстановочных знака: «*», который соответствует всем символам, **включая** разделитель иерархии (например, «/» в иерархии почтовых ящиков на основе каталогов на сервере Unix); и «%», который соответствует всем символам, **кроме** разделителя иерархии.
Если refname пусто, mailbox используется напрямую для определения, какие почтовые ящики подходят. Если mailbox пусто, возвращается корневое имя refname и разделитель иерархии.
Возвращаемое значение — массив Net::IMAP::MailboxList. Например:
imap.create("foo/bar")
imap.create("foo/baz")
p imap.list("", "foo/%")
#=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, \\
#<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, \\
#<Net::IMAP::MailboxList attr=[:Noinferiors], delim="/", name="foo/baz">]
# File lib/net/imap.rb, line 440
def login(user, password)
send_command("LOGIN", user, password)
end Отправляет команду LOGIN для идентификации клиента и содержит текстовое password для аутентификации этого user. Обратите внимание, что в отличие от вызова authenticate() с auth_type «LOGIN», login() **не** использует аутентификатор входа.
Если аутентификация завершится неудачей, возникает ошибка Net::IMAP::NoResponseError.
# File lib/net/imap.rb, line 373
def logout
send_command("LOGOUT")
end Отправляет команду LOGOUT, чтобы сообщить серверу, что клиент завершил работу с соединением.
# File lib/net/imap.rb, line 651
def lsub(refname, mailbox)
synchronize do
send_command("LSUB", refname, mailbox)
return @responses.delete("LSUB")
end
end Отправляет команду LSUB и возвращает подмножество имён из набора имён, которые пользователь объявил «активными» или «подписанными». refname и mailbox интерпретируются так же, как для list(). Возвращаемое значение — массив Net::IMAP::MailboxList.
# File lib/net/imap.rb, line 867
def move(set, mailbox)
copy_internal("MOVE", set, mailbox)
end Отправляет команду MOVE для перемещения указанных сообщений в конец указанного целевого mailbox. Параметр set — число, массив чисел или объект Range. Число — порядковый номер сообщения. Расширение MOVE протокола IMAP описано в [RFC-6851].
# File lib/net/imap.rb, line 367
def noop
send_command("NOOP")
end Отправляет команду NOOP на сервер. Она ничего не делает.
# File lib/net/imap.rb, line 911 def remove_response_handler(handler) @response_handlers.delete(handler) end
Удаляет обработчик ответов.
# File lib/net/imap.rb, line 500
def rename(mailbox, newname)
send_command("RENAME", mailbox, newname)
end Отправляет команду RENAME для изменения имени mailbox на newname.
Ошибка Net::IMAP::NoResponseError возникает, если почтовый ящик с именем mailbox не может быть переименован в newname по какой-либо причине; например, потому что mailbox не существует или потому, что уже существует почтовый ящик с именем newname.
# File lib/net/imap.rb, line 773
def search(keys, charset = nil)
return search_internal("SEARCH", keys, charset)
end Отправляет команду SEARCH для поиска сообщений в почтовом ящике, которые соответствуют заданным критериям поиска, и возвращает порядковые номера сообщений. keys может быть либо строкой, содержащей всю строку поиска, либо одномерным массивом поисковых ключевых слов и аргументов. Ниже приведены некоторые распространённые критерии поиска; полный список см. в разделе [IMAP] 6.4.4.
- <набор сообщений>
-
набор порядковых номеров сообщений. «,» обозначает интервал, «:» обозначает диапазон. Например, «2,10:12,15» означает «2,10,11,12,15».
- BEFORE <дата>
-
сообщения с внутренней датой строго до <дата>. Аргумент даты имеет формат, аналогичный 8-авг-2002.
- BODY <строка>
-
сообщения, содержащие <строка> в своём теле.
- CC <строка>
-
сообщения, содержащие <строка> в поле CC.
- FROM <строка>
-
сообщения, содержащие <строка> в поле FROM.
- NEW
-
сообщения со флагом Recent, но не флагом Seen.
- NOT <ключ-поиска>
-
отменить следующий ключ поиска.
- OR <ключ-поиска> <ключ-поиска>
-
соединить два ключа поиска по принципу «или».
- ON <дата>
-
сообщения с внутренней датой, точно равной <дата>, которая имеет формат, аналогичный 8-авг-2002.
- SINCE <дата>
-
сообщения с внутренней датой на или после <дата>.
- SUBJECT <строка>
-
сообщения с <строка> в теме.
- TO <строка>
-
сообщения с <строка> в поле TO.
Например:
p imap.search(["SUBJECT", "hello", "NOT", "NEW"]) #=> [1, 6, 7, 8]
# File lib/net/imap.rb, line 456
def select(mailbox)
synchronize do
@responses.clear
send_command("SELECT", mailbox)
end
end Отправляет команду SELECT для выбора mailbox, чтобы можно было получить доступ к сообщениям в этом mailbox.
После выбора почтового ящика вы можете получить количество элементов в этом почтовом ящике из @responses[-1] и количество последних сообщений из @responses[-1]. Обратите внимание, что эти значения могут измениться, если во время сессии придут новые сообщения; см. add_response_handler() для способа обнаружения этого события.
Если почтовый ящик не существует или по какой-либо причине недоступен для выбора, возникает ошибка Net::IMAP::NoResponseError.
# File lib/net/imap.rb, line 628
def setacl(mailbox, user, rights)
if rights.nil?
send_command("SETACL", mailbox, user, "")
else
send_command("SETACL", mailbox, user, rights)
end
end Отправляет команду SETACL вместе с mailbox, user и rights для пользователя в данном почтовом ящике. Если rights равно nil, права этого пользователя для данного почтового ящика будут удалены. Команды IMAP ACL описаны в [RFC-2086].
# File lib/net/imap.rb, line 615
def setquota(mailbox, quota)
if quota.nil?
data = '()'
else
data = '(STORAGE ' + quota.to_s + ')'
end
send_command("SETQUOTA", mailbox, RawData.new(data))
end Отправляет команду SETQUOTA вместе с указанными mailbox и quota. Если quota равно nil, то quota будет снято для этой почтовой папки. Обычно для этого требуется вход под учетной записью администратора сервера. Команды квоты IMAP описаны в [RFC-2087].
# File lib/net/imap.rb, line 885
def sort(sort_keys, search_keys, charset)
return sort_internal("SORT", sort_keys, search_keys, charset)
end Отправляет команду SORT для сортировки сообщений в почтовой папке. Возвращает массив номеров последовательности сообщений. Например:
p imap.sort(["FROM"], ["ALL"], "US-ASCII") #=> [1, 2, 3, 5, 6, 7, 8, 4, 9] p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII") #=> [6, 7, 8, 1]
Дополнительные сведения см. в [SORT-THREAD-EXT].
# File lib/net/imap.rb, line 378
def starttls(options = {}, verify = true)
send_command("STARTTLS") do |resp|
if resp.kind_of?(TaggedResponse) && resp.name == "OK"
begin
# for backward compatibility
certs = options.to_str
options = create_ssl_params(certs, verify)
rescue NoMethodError
end
start_tls_session(options)
end
end
end Отправляет команду STARTTLS для начала TLS-сессии.
# File lib/net/imap.rb, line 674
def status(mailbox, attr)
synchronize do
send_command("STATUS", mailbox, attr)
return @responses.delete("STATUS")[-1].attr
end
end Отправляет команду STATUS и возвращает состояние указанной mailbox. attr — список одной или нескольких характеристик, статус которых необходимо запросить. Поддерживаемые характеристики включают:
MESSAGES:: the number of messages in the mailbox. RECENT:: the number of recent messages in the mailbox. UNSEEN:: the number of unseen messages in the mailbox.
Возвращаемое значение — хеш характеристик. Например:
p imap.status("inbox", ["MESSAGES", "RECENT"])
#=> {"RECENT"=>0, "MESSAGES"=>44}
Исключение Net::IMAP::NoResponseError генерируется, если значения статуса для mailbox не могут быть возвращены; например, потому что они не существуют.
# File lib/net/imap.rb, line 840
def store(set, attr, flags)
return store_internal("STORE", set, attr, flags)
end Отправляет команду STORE для изменения данных, связанных с сообщениями в почтовой папке, в частности, их флагов. Параметр set — число, массив чисел или объект Range. Каждое число — номер последовательности сообщения. attr — имя элемента данных для сохранения: 'FLAGS' заменит список флагов сообщения предоставленным, '+FLAGS' добавит предоставленные флаги, а '-FLAGS' удалит их. flags — список флагов.
Возвращаемое значение — массив Net::IMAP::FetchData. Например:
p imap.store(6..8, "+FLAGS", [:Deleted])
#=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
#<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
#<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
# File lib/net/imap.rb, line 510
def subscribe(mailbox)
send_command("SUBSCRIBE", mailbox)
end Отправляет команду SUBSCRIBE для добавления указанного mailbox имени в набор «активных» или «подписанных» почтовых папок сервера, возвращаемых функцией lsub().
Исключение Net::IMAP::NoResponseError генерируется, если к mailbox невозможно подключиться; например, потому что оно не существует.
# File lib/net/imap.rb, line 928
def thread(algorithm, search_keys, charset)
return thread_internal("THREAD", algorithm, search_keys, charset)
end Аналогично search(), но возвращает номера последовательности сообщений в формате потоков в виде дерева Net::IMAP::ThreadMember. Поддерживаемые алгоритмы:
- ORDEREDSUBJECT
-
разбивает на потоки по одному уровню в соответствии с темой, отсортированные по дате.
- REFERENCES
-
разбивает на потоки по отношениям родитель/дочерний, определяющим, какое сообщение является ответом на какое.
В отличие от search(), charset является обязательным аргументом. Примеры значений — US-ASCII и UTF-8.
Дополнительные сведения см. в [SORT-THREAD-EXT].
Методы частного экземпляра
# File lib/net/imap.rb, line 1458 def copy_internal(cmd, set, mailbox) send_command(cmd, MessageSet.new(set), mailbox) end
# File lib/net/imap.rb, line 1497
def create_ssl_params(certs = nil, verify = true)
params = {}
if certs
if File.file?(certs)
params[:ca_file] = certs
elsif File.directory?(certs)
params[:ca_path] = certs
end
end
if verify
params[:verify_mode] = VERIFY_PEER
else
params[:verify_mode] = VERIFY_NONE
end
return params
end # File lib/net/imap.rb, line 1426
def fetch_internal(cmd, set, attr, mod = nil)
case attr
when String then
attr = RawData.new(attr)
when Array then
attr = attr.map { |arg|
arg.is_a?(String) ? RawData.new(arg) : arg
}
end
synchronize do
@responses.delete("FETCH")
if mod
send_command(cmd, MessageSet.new(set), attr, mod)
else
send_command(cmd, MessageSet.new(set), attr)
end
return @responses.delete("FETCH")
end
end # File lib/net/imap.rb, line 1282
def generate_tag
@tagno += 1
return format("%s%04d", @tag_prefix, @tagno)
end # File lib/net/imap.rb, line 1227
def get_response
buff = String.new
while true
s = @sock.gets(CRLF)
break unless s
buff.concat(s)
if /\{(\d+)\}\r\n/n =~ s
s = @sock.read($1.to_i)
buff.concat(s)
else
break
end
end
return nil if buff.length == 0
if @@debug
$stderr.print(buff.gsub(/^/n, "S: "))
end
return @parser.parse(buff)
end # File lib/net/imap.rb, line 1211
def get_tagged_response(tag, cmd)
until @tagged_responses.key?(tag)
raise @exception if @exception
@tagged_response_arrival.wait
end
resp = @tagged_responses.delete(tag)
case resp.name
when /\A(?:NO)\z/ni
raise NoResponseError, resp
when /\A(?:BAD)\z/ni
raise BadResponseError, resp
else
return resp
end
end # File lib/net/imap.rb, line 1486
def normalize_searching_criteria(keys)
keys.collect! do |i|
case i
when -1, Range, Array
MessageSet.new(i)
else
i
end
end
end # File lib/net/imap.rb, line 1287
def put_string(str)
@sock.print(str)
if @@debug
if @debug_output_bol
$stderr.print("C: ")
end
$stderr.print(str.gsub(/\n(?!\z)/n, "\nC: "))
if /\r\n\z/n.match(str)
@debug_output_bol = true
else
@debug_output_bol = false
end
end
end # File lib/net/imap.rb, line 1140
def receive_responses
connection_closed = false
until connection_closed
synchronize do
@exception = nil
end
begin
resp = get_response
rescue Exception => e
synchronize do
@sock.close
@exception = e
end
break
end
unless resp
synchronize do
@exception = EOFError.new("end of file reached")
end
break
end
begin
synchronize do
case resp
when TaggedResponse
@tagged_responses[resp.tag] = resp
@tagged_response_arrival.broadcast
case resp.tag
when @logout_command_tag
return
when @continued_command_tag
@continuation_request_exception =
RESPONSE_ERRORS[resp.name].new(resp)
@continuation_request_arrival.signal
end
when UntaggedResponse
record_response(resp.name, resp.data)
if resp.data.instance_of?(ResponseText) &&
(code = resp.data.code)
record_response(code.name, code.data)
end
if resp.name == "BYE" && @logout_command_tag.nil?
@sock.close
@exception = ByeResponseError.new(resp)
connection_closed = true
end
when ContinuationRequest
@continuation_request_arrival.signal
end
@response_handlers.each do |handler|
handler.call(resp)
end
end
rescue Exception => e
@exception = e
synchronize do
@tagged_response_arrival.broadcast
@continuation_request_arrival.broadcast
end
end
end
synchronize do
@receiver_thread_terminating = true
@tagged_response_arrival.broadcast
@continuation_request_arrival.broadcast
if @idle_done_cond
@idle_done_cond.signal
end
end
end
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.