Где 1С хранит адрес почты пользователя и как его прочитать

· 10 мин

Содержание

Email пользователя в типовых конфигурациях на БСП (Бухгалтерия 3.0, ЗУП 3.1, УТ 11) лежит не в пользователе информационной базы, а в табличной части КонтактнаяИнформация справочника Пользователи. Получить его проще всего запросом к этой табличной части с отбором по типу АдресЭлектроннойПочты, а текущего пользователя взять функцией Пользователи.ТекущийПользователь().

Если в карточке адрес не заполнен, есть три запасных источника. Учётная запись электронной почты из справочника УчетныеЗаписиЭлектроннойПочты подходит, когда нужен адрес отправителя. Active Directory через LDAP выбирают в доменной сети, где почта ведётся централизованно. HTTP-запрос к внешнему API нужен, если справочник сотрудников живёт в другой системе: кадровом портале или Microsoft 365.

Откуда 1С берёт адрес почты: метаданные и справочники

В платформе 1С:Предприятие 8.3 есть два разных «пользователя», и их часто путают.

  • 👤 Пользователь информационной базы — объект ПользовательИнформационнойБазы. Это логин, пароль, роли, привязка к учётной записи Windows. Его получают через ПользователиИнформационнойБазы.ТекущийПользователь(). Адрес почты типовые конфигурации здесь не ведут.
  • 📇 Элемент справочника Пользователи — прикладная карточка из Библиотеки стандартных подсистем (БСП). В ней ФИО, подразделение, физическое лицо и контактная информация. Email хранится здесь.

Связь между ними — реквизит ИдентификаторПользователяИБ в справочнике. Поэтому код, который ищет почту, всегда работает со ссылкой на СправочникСсылка.Пользователи.

Где адрес заполняют руками: Администрирование → Настройки пользователей и прав → Пользователи, открыть карточку, поле электронной почты в блоке контактной информации.

Как устроено хранение внутри:

ЧтоГде в метаданныхКомментарий
Строки контактной информацииСправочник.Пользователи.КонтактнаяИнформацияТабличная часть, по строке на каждый вид КИ
Тип строкиПоле Тип, перечисление ТипыКонтактнойИнформацииДля почты — АдресЭлектроннойПочты
Вид строкиПоле Вид, справочник ВидыКонтактнойИнформацииПредопределённый вид EmailПользователя
Сам адресПоле ПредставлениеСтрока вида ivanov@firma.ru

Отбирайте по полю Тип, а не только по Вид. Если администратор добавил свой вид почты, например «Рабочий email», отбор по EmailПользователя его пропустит.

У сотрудников есть ещё одна точка: реквизит ФизическоеЛицо в карточке пользователя. Контактная информация физического лица ведётся отдельно, в табличной части справочника ФизическиеЛица. В ЗУП там часто лежит личная почта для расчётных листков, и она может не совпадать с рабочей.

Получение email пользователя кодом через запрос

Запросы и обращения к справочникам выполняются на сервере. С клиента вызываем серверную функцию, она возвращает строку.

Адрес текущего пользователя

&НаСервереБезКонтекста
Функция EmailТекущегоПользователя()

	УстановитьПривилегированныйРежим(Истина);

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	КИ.Представление КАК Адрес
	|ИЗ
	|	Справочник.Пользователи.КонтактнаяИнформация КАК КИ
	|ГДЕ
	|	КИ.Ссылка = &Пользователь
	|	И КИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты)
	|
	|УПОРЯДОЧИТЬ ПО
	|	ВЫБОР
	|		КОГДА КИ.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.EmailПользователя)
	|			ТОГДА 0
	|		ИНАЧЕ 1
	|	КОНЕЦ,
	|	КИ.НомерСтроки";
	Запрос.УстановитьПараметр("Пользователь", Пользователи.ТекущийПользователь());

	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		Возврат СокрЛП(Выборка.Адрес);
	КонецЕсли;

	Возврат "";

КонецФункции

Что здесь важно:

  1. Пользователи.ТекущийПользователь() — функция общего модуля БСП. Она возвращает ссылку на элемент справочника, а не объект платформы.
  2. Сортировка ставит основной вид EmailПользователя первым. Если его нет, берётся первая строка любого почтового вида.
  3. УстановитьПривилегированныйРежим(Истина) нужен, если у роли пользователя нет права читать справочник целиком. В типовых конфигурациях такой код лучше вынести в серверный общий модуль, а не держать в модуле формы.

Адреса всех пользователей списком

Для рассылки или выгрузки удобнее один запрос на всех:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Пользователи.Ссылка КАК Пользователь,
|	Пользователи.Наименование КАК ФИО,
|	ЕСТЬNULL(КИ.Представление, """") КАК Адрес
|ИЗ
|	Справочник.Пользователи КАК Пользователи
|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Пользователи.КонтактнаяИнформация КАК КИ
|		ПО (КИ.Ссылка = Пользователи.Ссылка)
|			И (КИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты))
|ГДЕ
|	НЕ Пользователи.ПометкаУдаления
|	И НЕ Пользователи.Недействителен
|	И НЕ Пользователи.Служебный
|
|УПОРЯДОЧИТЬ ПО
|	ФИО";
Таблица = Запрос.Выполнить().Выгрузить();

Левое соединение оставляет в выборке пользователей без почты: у них в колонке Адрес будет пустая строка. По ней удобно найти, кому заполнить карточку. Если у человека два почтовых адреса, он попадёт в таблицу двумя строками.

Отбор по Недействителен и Служебный убирает уволенных и технических пользователей вроде обмена данными. Без него рассылка уйдёт и на служебные учётки.

Через программный интерфейс БСП

В модуле УправлениеКонтактнойИнформацией есть функции для чтения КИ объекта. Их состав и параметры менялись между версиями БСП, поэтому перед использованием откройте модуль в конфигураторе и найдите экспортную функцию по слову «КонтактнаяИнформация». Прямой запрос из примера выше работает одинаково во всех актуальных релизах.

Email из учётной записи электронной почты

Бывает, что нужен не адрес из карточки, а адрес, с которого пользователь реально отправляет письма из 1С. Он хранится в справочнике УчетныеЗаписиЭлектроннойПочты, реквизит АдресЭлектроннойПочты.

В современных версиях БСП учётная запись может быть личной: у неё заполнен владелец — пользователь. Тогда адрес отправителя находится запросом с отбором по владельцу. Если владельца нет, учётная запись общая, например buh@firma.ru, и к конкретному человеку её не привязать.

Когда какой источник брать:

ЗадачаИсточник
Уведомить пользователя о событииКонтактная информация справочника Пользователи
Подставить «От кого» в письмоУчётная запись электронной почты
Отправить расчётный листок сотрудникуКонтактная информация физического лица

История изменений адреса и регистры сведений

В текущих конфигурациях отдельного регистра под контактную информацию пользователей нет: всё лежит в табличной части справочника. Регистр сведений КонтактнаяИнформация встречается в старых решениях эпохи 8.2 — УТ 10.3, ЗУП 2.5, Бухгалтерии 2.0. Там адрес читают запросом к регистру с отбором по измерениям Объект и Тип, а значение берут из ресурса Представление.

Историю изменения адреса в типовых конфигурациях на 8.3 можно восстановить двумя способами:

  • 🗂 Версионирование объектов. Если в настройках программы включено хранение версий для справочника «Пользователи», каждая запись карточки сохраняется в регистр сведений ВерсииОбъектов. В карточке пользователя это видно через команду истории изменений, а версии можно сравнить между собой.
  • 📜 Журнал регистрации. В нём фиксируется факт изменения элемента справочника, кто и когда его записал. Старое значение адреса журнал не хранит, только событие.

Хранение истории с датой действия в табличной части КИ поддерживается для адресов, а не для почты. Если важно знать, какой email был у пользователя на прошлую дату, включайте версионирование.

Получение почты из Active Directory через LDAP

В доменной сети адрес почты часто уже лежит в атрибуте mail учётной записи AD. Встроенного объекта для LDAP в платформе нет, но на Windows-сервере работает COM-провайдер ADsDSOObject.

Сначала узнаём логин пользователя в Windows. Свойство ПользовательОС возвращает строку вида \\CORP\ivanov, из неё нужна последняя часть:

ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
Части = СтрРазделить(ПользовательИБ.ПользовательОС, "\", Ложь);
Логин = ?(Части.Количество() > 0, Части[Части.Количество() - 1], "");

Затем ищем запись в каталоге:

Функция EmailИзActiveDirectory(Логин) Экспорт

	Адрес = "";
	Попытка
		Соединение = Новый COMОбъект("ADODB.Connection");
		Соединение.Provider = "ADsDSOObject";
		Соединение.Open("Active Directory Provider");

		Команда = Новый COMОбъект("ADODB.Command");
		Команда.ActiveConnection = Соединение;
		Команда.CommandText = "<LDAP://DC=corp,DC=local>;"
			+ "(&(objectCategory=person)(objectClass=user)(sAMAccountName=" + Логин + "));"
			+ "mail;subtree";

		Записи = Команда.Execute();
		Если Не Записи.EOF Тогда
			Значение = Записи.Fields("mail").Value;
			Если Значение <> Неопределено И Значение <> NULL Тогда
				Адрес = СокрЛП(Строка(Значение));
			КонецЕсли;
		КонецЕсли;
		Записи.Close();
		Соединение.Close();
	Исключение
		ЗаписьЖурналаРегистрации("Интеграция.ActiveDirectory",
			УровеньЖурналаРегистрации.Ошибка, , ,
			ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;

	Возврат Адрес;

КонецФункции

DC=corp,DC=local замените на свой домен. Что учесть:

  1. Где выполняется код. В клиент-серверном варианте функция работает на сервере 1С, под учётной записью службы агента. У этой учётки должны быть права на чтение каталога. Локальная системная учётная запись на рядовом сервере в домен часто не ходит.
  2. Только Windows. COM-объекты на сервере 1С под Linux недоступны. Там используют HTTP-шлюз к каталогу или выгрузку атрибутов по расписанию.
  3. Экранирование. Логин подставляется в фильтр LDAP. Символы *, (, ) и \ в нём нужно экранировать, иначе фильтр вернёт чужие записи.
  4. Пустой mail. Если почтовый ящик заведён в Exchange, но атрибут не заполнен, смотрите userPrincipalName или proxyAddresses. Основной адрес в proxyAddresses идёт с префиксом SMTP: в верхнем регистре.

Не ходите в AD при каждом открытии формы. Надёжнее раз в сутки регламентным заданием переносить адреса в контактную информацию пользователей и дальше читать их обычным запросом.

Адрес через HTTP-запрос к внешнему API

Если учётные записи ведутся в облаке или кадровом портале, адрес берут по HTTP. Пример для Microsoft Graph: приложению в Entra ID нужно право User.Read.All, токен получаете заранее по схеме client credentials.

Функция EmailИзMicrosoftGraph(ИмяВхода, Токен) Экспорт

	Соединение = Новый HTTPСоединение("graph.microsoft.com", 443,,,, 30,
		Новый ЗащищенноеСоединениеOpenSSL);

	Адрес = "/v1.0/users/"
		+ КодироватьСтроку(ИмяВхода, СпособКодированияСтроки.КодировкаURL)
		+ "?$select=mail,userPrincipalName";
	Запрос = Новый HTTPЗапрос(Адрес);
	Запрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
	Запрос.Заголовки.Вставить("Accept", "application/json");

	Попытка
		Ответ = Соединение.Получить(Запрос);
	Исключение
		ЗаписьЖурналаРегистрации("Интеграция.Graph", УровеньЖурналаРегистрации.Ошибка, , ,
			ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат "";
	КонецПопытки;

	Если Ответ.КодСостояния <> 200 Тогда
		ЗаписьЖурналаРегистрации("Интеграция.Graph", УровеньЖурналаРегистрации.Предупреждение, , ,
			СтрШаблон("Код ответа %1: %2", Формат(Ответ.КодСостояния, "ЧГ=0"),
				Ответ.ПолучитьТелоКакСтроку("UTF-8")));
		Возврат "";
	КонецЕсли;

	Чтение = Новый ЧтениеJSON;
	Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку("UTF-8"));
	Данные = ПрочитатьJSON(Чтение, Истина);
	Чтение.Закрыть();

	Почта = Данные.Получить("mail");
	Возврат ?(ЗначениеЗаполнено(Почта), СокрЛП(Почта), "");

КонецФункции

Почему именно так:

  • 🔑 ПрочитатьJSON(Чтение, Истина) читает ответ в Соответствие. В структуру прочитать не получится: ключ @odata.context не является допустимым именем свойства, и платформа выдаст ошибку.
  • 🧾 Поле mail в ответе может быть null. Он превращается в Неопределено, и ЗначениеЗаполнено это отсекает.
  • ⏱ Таймаут 30 секунд не даёт форме зависнуть, если внешний сервис не отвечает.
  • 🔒 Токен не храните в константе открытым текстом. В БСП для секретов есть безопасное хранилище данных — в нём же типовые конфигурации держат пароли учётных записей почты.

Для своего кадрового портала схема та же: другой хост, другой путь, своя авторизация.

Проверка адреса и обработка ошибок

Полученная строка ещё не гарантирует, что письмо дойдёт. В поле КИ пользователи вписывают что угодно: два адреса через запятую, пробелы, «нет».

Минимальная проверка своими силами:

Функция ПохожеНаEmail(Знач Адрес)

	Адрес = СокрЛП(Адрес);
	Если СтрНайти(Адрес, " ") > 0 Или СтрЧислоВхождений(Адрес, "@") <> 1 Тогда
		Возврат Ложь;
	КонецЕсли;

	Части = СтрРазделить(Адрес, "@");
	Возврат СтрДлина(Части[0]) > 0 И СтрНайти(Части[1], ".") > 1
		И Не СтрЗаканчиваетсяНа(Части[1], ".");

КонецФункции

В БСП есть готовая функция ОбщегоНазначенияКлиентСервер.АдресЭлектроннойПочтыСоответствуетТребованиям. Она строже самописной проверки, и в типовой конфигурации лучше вызывать её.

Если в поле может быть несколько адресов, сначала разбейте строку по ; и , через СтрРазделить, затем проверьте каждый адрес отдельно.

Диагностика: выберите симптом

Что делать, если адреса нет нигде: не подставляйте «заглушку» и не шлите письмо в пустоту. Верните пустую строку, запишите событие в журнал регистрации с указанием пользователя и покажите администратору список людей без почты. Этот список даёт запрос из второго раздела.

Частые вопросы

Есть ли в 1С функция вроде ТекущийEmail()?
Нет. Платформа знает только имя и полное имя пользователя через ИмяПользователя() и ПолноеИмяПользователя(). Адрес почты — прикладные данные конфигурации, его читают из справочника.
Можно ли получить email пользователя в конфигурации без БСП?
Да, если разработчик сам добавил реквизит или табличную часть под почту. Откройте справочник пользователей в конфигураторе и найдите, где лежит адрес. Если места нет — добавьте реквизит, лучше через расширение.
Как получить почту внешнего пользователя?
Внешние пользователи хранятся в справочнике ВнешниеПользователи и ссылаются на объект авторизации: контрагента или контактное лицо. Почту берут из контактной информации этого объекта. Ссылку на текущего вернёт Пользователи.АвторизованныйПользователь().
Почему у пользователя два адреса и какой брать?
В карточке можно завести несколько строк почтового типа. Берите вид EmailПользователя, а остальные — только если основного нет. Так устроена сортировка в первом примере.
Сработает ли запрос в файловой базе?
Да. Запрос к табличной части одинаково выполняется в файловом и клиент-серверном варианте. Ограничения касаются только COM: в файловой базе код выполняется на компьютере пользователя, и права на чтение AD будут у его учётной записи.