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